我们还建议重启所有组件(例如 kube-scheduler、kube-controller-manager、kubelet),以确保它们不会
依赖一些过时的数据。请注意,实际中还原会花费一些时间。
在还原过程中,关键组件将丢失领导锁并自行重启。
说明: Kubernetes 的节点可以按照 Capacity 调度。默认情况下 pod 能够使用节点全部可用容量。
这是个问题,因为节点自己通常运行了不少驱动 OS 和 Kubernetes 的系统守护进程。
除非为这些系统守护进程留出资源,否则它们将与 pod 争夺资源并导致节点资源短缺问题。
kubelet 公开了一个名为 Node Allocatable 的特性,有助于为系统守护进程预留计算资源。
Kubernetes 推荐集群管理员按照每个节点上的工作负载密度配置 Node Allocatable。
准备开始
你必须拥有一个 Kubernetes 的集群,同时你的 Kubernetes 集群必须带有 kubectl 命令行工具。
如果你还没有集群,你可以通过 Minikube 构建一
个你自己的集群,或者你可以使用下面任意一个 Kubernetes 工具构建:
您的 Kubernetes 服务器版本必须不低于版本 1.8.
要获知版本信息,请输入
kubectl version.
您的 kubernetes 服务器版本必须至少是 1.17 版本,才能使用 kubelet
命令行选项 --reserved-cpus 设置
显式预留 CPU 列表 。
节点可分配
Kubernetes 节点上的 Allocatable 被定义为 pod 可用计算资源量。
调度器不会超额申请 Allocatable。
目前支持 CPU, memory 和 ephemeral-storage 这几个参数。
可分配的节点暴露为 API 中 v1.Node 对象的一部分,也是 CLI 中
kubectl describe node 的一部分。
在 kubelet 中,可以为两类系统守护进程预留资源。
启用 QoS 和 Pod 级别的 cgroups 为了恰当的在节点范围实施节点可分配约束,你必须通过 --cgroups-per-qos
标志启用新的 cgroup 层次结构。这个标志是默认启用的。
启用后,kubelet 将在其管理的 cgroup 层次结构中创建所有终端用户的 Pod。
配置 cgroup 驱动 kubelet 支持在主机上使用 cgroup 驱动操作 cgroup 层次结构。
驱动通过 --cgroup-driver 标志配置。
支持的参数值如下:
cgroupfs 是默认的驱动,在主机上直接操作 cgroup 文件系统以对 cgroup
沙箱进行管理。systemd 是可选的驱动,使用 init 系统支持的资源的瞬时切片管理
cgroup 沙箱。取决于相关容器运行时的配置,操作员可能需要选择一个特定的 cgroup 驱动
来保证系统正常运行。
例如,如果操作员使用 docker 运行时提供的 systemd cgroup 驱动时,
必须配置 kubelet 使用 systemd cgroup 驱动。
Kube 预留值 Kubelet 标志 : --kube-reserved=[cpu=100m][,][memory=100Mi][,][ephemeral-storage=1Gi][,][pid=1000]Kubelet 标志 : --kube-reserved-cgroup=kube-reserved 用来给诸如 kubelet、容器运行时、节点问题监测器等
kubernetes 系统守护进程记述其资源预留值。
该配置并非用来给以 Pod 形式运行的系统守护进程保留资源。kube-reserved
通常是节点上 pod 密度 的函数。
除了 cpu,内存 和 ephemeral-storage 之外,pid 可用来指定为
kubernetes 系统守护进程预留指定数量的进程 ID。
要选择性地对 kubernetes 系统守护进程上执行 kube-reserved 保护,需要把 kubelet 的
--kube-reserved-cgroup 标志的值设置为 kube 守护进程的父控制组。
推荐将 kubernetes 系统守护进程放置于顶级控制组之下(例如 systemd 机器上的
runtime.slice)。
理想情况下每个系统守护进程都应该在其自己的子控制组中运行。
请参考
这篇文档 ,
进一步了解关于推荐控制组层次结构的细节。
请注意,如果 --kube-reserved-cgroup 不存在,Kubelet 将 不会 创建它。
如果指定了一个无效的 cgroup,Kubelet 将会失败。
系统预留值 Kubelet 标志 : --system-reserved=[cpu=100m][,][memory=100Mi][,][ephemeral-storage=1Gi][,][pid=1000]Kubelet 标志 : --system-reserved-cgroup=system-reserved 用于为诸如 sshd、udev 等系统守护进程记述其资源预留值。
system-reserved 也应该为 kernel 预留 内存,因为目前 kernel
使用的内存并不记在 Kubernetes 的 Pod 上。
同时还推荐为用户登录会话预留资源(systemd 体系中的 user.slice)。
除了 cpu,内存 和 ephemeral-storage 之外,pid 可用来指定为
kubernetes 系统守护进程预留指定数量的进程 ID。
要想为系统守护进程上可选地实施 system-reserved 约束,请指定 kubelet 的
--system-reserved-cgroup 标志值为 OS 系统守护进程的父级控制组。
推荐将 OS 系统守护进程放在一个顶级控制组之下(例如 systemd 机器上的
system.slice)。
请注意,如果 --system-reserved-cgroup 不存在,Kubelet 不会 创建它。
如果指定了无效的 cgroup,Kubelet 将会失败。
显式保留的 CPU 列表 FEATURE STATE: Kubernetes v1.17 [stable]
Kubelet 标志 : --reserved-cpus=0-3reserved-cpus 旨在为操作系统守护程序和 kubernetes 系统守护程序保留一组明确指定编号的
CPU。reserved-cpus 适用于不打算针对 cpuset 资源为操作系统守护程序和 kubernetes
系统守护程序定义独立的顶级 cgroups 的系统。
如果 Kubelet 没有 指定参数 --system-reserved-cgroup 和 --kube-reserved-cgroup,
则 reserved-cpus 的设置将优先于 --kube-reserved 和 --system-reserved 选项。
此选项是专门为电信/NFV 用例设计的,在这些用例中不受控制的中断或计时器可能会
影响其工作负载性能。
你可以使用此选项为系统或 kubernetes 守护程序以及中断或计时器显式定义 cpuset,
这样系统上的其余 CPU 可以专门用于工作负载,因不受控制的中断或计时器的影响得以
降低。
要将系统守护程序、kubernetes 守护程序和中断或计时器移动到此选项定义的显式
cpuset 上,应使用 Kubernetes 之外的其他机制。
例如:在 Centos 系统中,可以使用 tuned 工具集来执行此操作。
驱逐阈值 Kubelet 标志 : --eviction-hard=[memory.available<500Mi]节点级别的内存压力将导致系统内存不足,这将影响到整个节点及其上运行的所有 Pod。
节点可以暂时离线直到内存已经回收为止。
为了防止(或减少可能性)系统内存不足,kubelet 提供了
资源不足 管理。
驱逐操作只支持 memory 和 ephemeral-storage。
通过 --eviction-hard 标志预留一些内存后,当节点上的可用内存降至保留值以下时,
kubelet 将尝试驱逐 Pod。
如果节点上不存在系统守护进程,Pod 将不能使用超过 capacity-eviction-hard 所
指定的资源量。因此,为驱逐而预留的资源对 Pod 是不可用的。
实施节点可分配约束 Kubelet 标志 : --enforce-node-allocatable=pods[,][system-reserved][,][kube-reserved]调度器将 Allocatable 视为 Pod 可用的 capacity(资源容量)。
kubelet 默认对 Pod 执行 Allocatable 约束。
无论何时,如果所有 Pod 的总用量超过了 Allocatable,驱逐 Pod 的措施将被执行。
有关驱逐策略的更多细节可以在
这里 找到。
可通过设置 kubelet --enforce-node-allocatable 标志值为 pods 控制这个措施。
可选地,通过在同一标志中同时指定 kube-reserved 和 system-reserved 值,
可以使 kubelet 强制实施 kube-reserved 和 system-reserved约束。
请注意,要想执行 kube-reserved 或者 system-reserved 约束,
需要对应设置 --kube-reserved-cgroup 或者 --system-reserved-cgroup。
一般原则 系统守护进程一般会被按照类似 Guaranteed Pod 一样对待。
系统守护进程可以在与其对应的控制组中出现突发资源用量,这一行为要作为
kubernetes 部署的一部分进行管理。
例如,kubelet 应该有它自己的控制组并和容器运行时共享 Kube-reserved 资源。
不过,如果执行了 kube-reserved 约束,则 kubelet 不可出现突发负载并用光
节点的所有可用资源。
在执行 system-reserved 预留策略时请加倍小心,因为它可能导致节点上的
关键系统服务出现 CPU 资源短缺、因为内存不足而被终止或者无法在节点上创建进程。
建议只有当用户详尽地描述了他们的节点以得出精确的估计值,
并且对该组中进程因内存不足而被杀死时,有足够的信心将其恢复时,
才可以强制执行 system-reserved 策略。
作为起步,可以先针对 pods 上执行 Allocatable 约束。 一旦用于追踪系统守护进程的监控和告警的机制到位,可尝试基于用量估计的
方式执行 kube-reserved策略。 随着时间推进,在绝对必要的时候可以执行 system-reserved 策略。 随着时间推进和越来越多特性被加入,kube 系统守护进程对资源的需求可能也会增加。
以后 kubernetes 项目将尝试减少对节点系统守护进程的利用,但目前这件事的优先级
并不是最高。
所以,将来的发布版本中 Allocatable 容量是有可能降低的。
示例场景 这是一个用于说明节点可分配(Node Allocatable)计算方式的示例:
节点拥有 32Gi memeory,16 CPU 和 100Gi Storage 资源 --kube-reserved 被设置为 cpu=1,memory=2Gi,ephemeral-storage=1Gi--system-reserved 被设置为 cpu=500m,memory=1Gi,ephemeral-storage=1Gi--eviction-hard 被设置为 memory.available<500Mi,nodefs.available<10%在这个场景下,Allocatable 将会是 14.5 CPUs、28.5Gi 内存以及 88Gi 本地存储。
调度器保证这个节点上的所有 Pod 的内存 requests 总量不超过 28.5Gi,
存储不超过 88Gi。
当 Pod 的内存使用总量超过 28.5Gi 或者磁盘使用总量超过 88Gi 时,
kubelet 将会驱逐它们。
如果节点上的所有进程都尽可能多地使用 CPU,则 Pod 加起来不能使用超过
14.5 CPUs 的资源。
当没有执行 kube-reserved 和/或 system-reserved 策略且系统守护进程
使用量超过其预留时,如果节点内存用量高于 31.5Gi 或存储大于 90Gi,
kubelet 将会驱逐 Pod。
4.2.10 - 为节点发布扩展资源 本文展示了如何为节点指定扩展资源(Extended Resource)。
扩展资源允许集群管理员发布节点级别的资源,这些资源在不进行发布的情况下无法被 Kubernetes 感知。
准备开始
你必须拥有一个 Kubernetes 的集群,同时你的 Kubernetes 集群必须带有 kubectl 命令行工具。
如果你还没有集群,你可以通过 Minikube 构建一
个你自己的集群,或者你可以使用下面任意一个 Kubernetes 工具构建:
要获知版本信息,请输入
kubectl version.
获取你的节点名称 选择一个节点用于此练习。
在你的一个节点上发布一种新的扩展资源 为在一个节点上发布一种新的扩展资源,需要发送一个 HTTP PATCH 请求到 Kubernetes API server。
例如:假设你的一个节点上带有四个 dongle 资源。
下面是一个 PATCH 请求的示例,该请求为你的节点发布四个 dongle 资源。
PATCH /api/v1/nodes/<your-node-name>/status HTTP/1.1
Accept: application/json
Content-Type: application/json-patch+json
Host: k8s-master:8080
[
{
"op" : "add" ,
"path" : "/status/capacity/example.com~1dongle" ,
"value" : "4"
}
]
注意:Kubernetes 不需要了解 dongle 资源的含义和用途。
前面的 PATCH 请求仅仅告诉 Kubernetes 你的节点拥有四个你称之为 dongle 的东西。
启动一个代理(proxy),以便你可以很容易地向 Kubernetes API server 发送请求:
在另一个命令窗口中,发送 HTTP PATCH 请求。 用你的节点名称替换 <your-node-name>:
curl --header "Content-Type: application/json-patch+json" \
--request PATCH \
--data '[{"op": "add", "path": "/status/capacity/example.com~1dongle", "value": "4"}]' \
http://localhost:8001/api/v1/nodes/<your-node-name>/status
说明: 在前面的请求中,
~1 为 patch 路径中 “/” 符号的编码。
JSON-Patch 中的操作路径值被解析为 JSON 指针。
更多细节,请查看
IETF RFC 6901 的第 3 节。
输出显示该节点的 dongle 资源容量(capacity)为 4:
"capacity": {
"cpu": "2",
"memory": "2049008Ki",
"example.com/dongle": "4",
描述你的节点:
kubectl describe node <your-node-name>
输出再次展示了 dongle 资源:
Capacity :
cpu : 2
memory : 2049008Ki
example.com/dongle : 4
现在,应用开发者可以创建请求一定数量 dongle 资源的 Pod 了。
参见将扩展资源分配给容器 。
讨论 扩展资源类似于内存和 CPU 资源。例如,正如一个节点拥有一定数量的内存和 CPU 资源,
它们被节点上运行的所有组件共享,该节点也可以拥有一定数量的 dongle 资源,
这些资源同样被节点上运行的所有组件共享。
此外,正如应用开发者可以创建请求一定数量的内存和 CPU 资源的 Pod,
他们也可以创建请求一定数量 dongle 资源的 Pod。
扩展资源对 Kubernetes 是不透明的。Kubernetes 不知道扩展资源含义相关的任何信息。
Kubernetes 只了解一个节点拥有一定数量的扩展资源。
扩展资源必须以整形数量进行发布。
例如,一个节点可以发布 4 个 dongle 资源,但是不能发布 4.5 个。
存储示例 假设一个节点拥有一种特殊类型的磁盘存储,其容量为 800 GiB。
你可以为该特殊存储创建一个名称,如 example.com/special-storage。
然后你就可以按照一定规格的块(如 100 GiB)对其进行发布。
在这种情况下,你的节点将会通知它拥有八个 example.com/special-storage 类型的资源。
Capacity :
...
example.com/special-storage : 8
如果你想要允许针对特殊存储任意(数量)的请求,你可以按照 1 字节大小的块来发布特殊存储。
在这种情况下,你将会发布 800Gi 数量的 example.com/special-storage 类型的资源。
Capacity :
...
example.com/special-storage : 800Gi
然后,容器就能够请求任意数量(多达 800Gi)字节的特殊存储。
Capacity :
...
example.com/special-storage : 800Gi
清理 这里是一个从节点移除 dongle 资源发布的 PATCH 请求。
PATCH /api/v1/nodes/<your-node-name>/status HTTP/1.1
Accept: application/json
Content-Type: application/json-patch+json
Host: k8s-master:8080
[
{
"op": "remove",
"path": "/status/capacity/example.com~1dongle",
}
]
启动一个代理,以便你可以很容易地向 Kubernetes API 服务器发送请求:
在另一个命令窗口中,发送 HTTP PATCH 请求。用你的节点名称替换 <your-node-name>:
curl --header "Content-Type: application/json-patch+json" \
--request PATCH \
--data '[{"op": "remove", "path": "/status/capacity/example.com~1dongle"}]' \
http://localhost:8001/api/v1/nodes/<your-node-name>/status
验证 dongle 资源的发布已经被移除:
kubectl describe node <your-node-name> | grep dongle
(你应该看不到任何输出)
接下来 针对应用开发人员 针对集群管理员 4.2.11 - 使用 CoreDNS 进行服务发现 此页面介绍了 CoreDNS 升级过程以及如何安装 CoreDNS 而不是 kube-dns。
准备开始
你必须拥有一个 Kubernetes 的集群,同时你的 Kubernetes 集群必须带有 kubectl 命令行工具。
如果你还没有集群,你可以通过 Minikube 构建一
个你自己的集群,或者你可以使用下面任意一个 Kubernetes 工具构建:
您的 Kubernetes 服务器版本必须不低于版本 v1.9.
要获知版本信息,请输入
kubectl version.
关于 CoreDNS CoreDNS 是一个灵活可扩展的 DNS 服务器,可以作为 Kubernetes 集群 DNS。
与 Kubernetes 一样,CoreDNS 项目由 CNCF 托管。
通过在现有的集群中替换 kube-dns,可以在集群中使用 CoreDNS 代替 kube-dns 部署,
或者使用 kubeadm 等工具来为你部署和升级集群。
安装 CoreDNS 有关手动部署或替换 kube-dns,请参阅
CoreDNS GitHub 工程 。
迁移到 CoreDNS 使用 kubeadm 升级现有集群 在 Kubernetes 1.10 及更高版本中,当你使用 kubeadm 升级使用 kube-dns 的集群时,你还可以迁移到 CoreDNS。
在本例中 kubeadm 将生成 CoreDNS 配置("Corefile")基于 kube-dns ConfigMap,
保存联邦、存根域和上游名称服务器的配置。
如果你正在从 kube-dns 迁移到 CoreDNS,请确保在升级期间将 CoreDNS 特性门设置为 true。
例如,v1.11.0 升级应该是这样的:
kubeadm upgrade apply v1.11.0 --feature-gates=CoreDNS=true
在 Kubernetes 版本 1.13 和更高版本中,CoreDNS特性门已经删除,CoreDNS 在默认情况下使用。
如果你想升级集群以使用 kube-dns,请遵循
此处 。
在 1.11 之前的版本中,核心文件将被升级过程中创建的文件覆盖。
如果已对其进行自定义,则应保存现有的 ConfigMap。
在新的 ConfigMap 启动并运行后,你可以重新应用自定义。
如果你在 Kubernetes 1.11 及更高版本中运行 CoreDNS,则在升级期间,将保留现有的 Corefile。
使用 kubeadm 安装 kube-dns 而不是 CoreDNS 说明: 在 Kubernetes 1.11 中,CoreDNS 已经升级到通用可用性(GA),并默认安装。
警告: 在 Kubernetes 1.18 中,用 kubeadm 来安装 kube-dns 这一做法已经被废弃,
会在将来版本中移除。
若要在 1.13 之前版本上安装 kube-dns,请将 CoreDNS 特性门控设置为 false:
kubeadm init --feature-gates= CoreDNS = false
对于 1.13 版和更高版本,请遵循
此处 概述到指南。
升级 CoreDNS 从 v1.9 起,Kubernetes 提供了 CoreDNS。
你可以在此处
查看 Kubernetes 随附的 CoreDNS 版本以及对 CoreDNS 所做的更改。
如果你只想升级 CoreDNS 或使用自己的自定义镜像,则可以手动升级 CoreDNS。
参看指南和演练
文档了解如何平滑升级。
CoreDNS 调优 当资源利用方面有问题时,优化 CoreDNS 的配置可能是有用的。
有关详细信息,请参阅有关扩缩 CoreDNS 的文档 。
接下来 你可以通过修改 Corefile 来配置 CoreDNS ,以支持比 kube-dns 更多的用例。
请参考 CoreDNS 网站
以了解更多信息。
4.2.12 - 使用 KMS 驱动进行数据加密 本页展示了如何配置秘钥管理服务—— Key Management Service (KMS) 驱动和插件以启用
Secret 数据加密。
准备开始 需要 Kubernetes 1.10.0 或更新版本 需要 etcd v3 或更新版本 FEATURE STATE: Kubernetes v1.12 [beta]
KMS 加密驱动使用封套加密模型来加密 etcd 中的数据。
数据使用数据加密秘钥(DEK)加密;每次加密都生成一个新的 DEK。
这些 DEK 经一个秘钥加密秘钥(KEK)加密后在一个远端的 KMS 中存储和管理。
KMS 驱动使用 gRPC 与一个特定的 KMS 插件通信。这个 KMS 插件作为一个 gRPC
服务器被部署在 Kubernetes 主服务器的同一个主机上,负责与远端 KMS 的通信。
配置 KMS 驱动 为了在 API 服务器上配置 KMS 驱动,在加密配置文件中的驱动数组中加入一个类型为 kms
的驱动,并设置下列属性:
name: KMS 插件的显示名称。endpoint: gRPC 服务器(KMS 插件)的监听地址。该端点是一个 UNIX 域套接字。cachesize: 以明文缓存的数据加密秘钥(DEKs)的数量。一旦被缓存,
就可以直接使用 DEKs 而无需另外调用 KMS;而未被缓存的 DEKs 需要调用一次 KMS 才能解包。timeout: 在返回一个错误之前,kube-apiserver 等待 kms-plugin 响应的时间(默认是 3 秒)。参见理解静态数据加密配置
实现 KMS 插件 为实现一个 KMS 插件,你可以开发一个新的插件 gRPC 服务器或启用一个由你的云服务驱动提供的 KMS 插件。
你可以将这个插件与远程 KMS 集成,并把它部署到 Kubernetes 的主服务器上。
启用由云服务驱动支持的 KMS 有关启用云服务驱动特定的 KMS 插件的说明,请咨询你的云服务驱动商。
开发 KMS 插件 gRPC 服务器 你可以使用 Go 语言的存根文件开发 KMS 插件 gRPC 服务器。
对于其他语言,你可以用 proto 文件创建可以用于开发 gRPC 服务器代码的存根文件。
使用 Go 以外的其他语言:用 protoc 编译器编译 proto 文件:
service.proto
为指定语言生成存根文件。 然后使用存根文件中的函数和数据结构开发服务器代码。
注意:
将 KMS 插件与远程 KMS 整合 KMS 插件可以用任何受 KMS 支持的协议与远程 KMS 通信。
所有的配置数据,包括 KMS 插件用于与远程 KMS 通信的认证凭据,都由 KMS 插件独立地存储和管理。
KMS 插件可以用额外的元数据对密文进行编码,这些元数据是在把它发往 KMS 进行解密之前可能要用到的。
部署 KMS 插件 确保 KMS 插件与 Kubernetes 主服务器运行在同一主机上。
使用 KMS 驱动加密数据 为了加密数据:
使用 kms 驱动的相应的属性创建一个新的加密配置文件:
kind : EncryptionConfiguration
apiVersion : apiserver.config.k8s.io/v1
resources :
- resources :
- secrets
providers :
- kms :
name : myKmsPlugin
endpoint : unix:///tmp/socketfile.sock
cachesize : 100
timeout : 3s
- identity : {}
设置 kube-apiserver 的 --encryption-provider-config 参数指向配置文件的位置。 重启 API 服务器。 验证数据已经加密 写入 etcd 时数据被加密。重启 kube-apiserver 后,任何新建或更新的 Secret 在存储时应该已被加密。
要验证这点,你可以用 etcdctl 命令行程序获取 Secret 内容。
在默认的命名空间里创建一个名为 secret1 的 Secret:
kubectl create secret generic secret1 -n default --from-literal=mykey=mydata
用 etcdctl 命令行,从 etcd 读取出 Secret:
ETCDCTL_API=3 etcdctl get /kubernetes.io/secrets/default/secret1 [...] | hexdump -C
其中 [...] 是用于连接 etcd 服务器的额外参数。
验证保存的 Secret 是否是以 k8s:enc:kms:v1: 开头的,这表明 kms 驱动已经对结果数据加密。 验证 Secret 在被 API 获取时已被正确解密:
kubectl describe secret secret1 -n default
结果应该是 mykey: mydata。
确保所有 Secret 都已被加密 因为 Secret 是在写入时被加密的,所以在更新 Secret 时也会加密该内容。
下列命令读取所有 Secret 并更新它们以便应用服务器端加密。如果因为写入冲突导致错误发生,
请重试此命令。对较大的集群,你可能希望根据命名空间或脚本更新去细分 Secret 内容。
kubectl get secrets --all-namespaces -o json | kubectl replace -f -
从本地加密驱动切换到 KMS 驱动 为了从本地加密驱动切换到 kms 驱动并重新加密所有 Secret 内容:
在配置文件中加入 kms 驱动作为第一个条目,如下列样例所示
kind : EncryptionConfiguration
apiVersion : apiserver.config.k8s.io/v1
resources :
- resources :
- secrets
providers :
- kms :
name : myKmsPlugin
endpoint : unix:///tmp/socketfile.sock
cachesize : 100
- aescbc :
keys :
- name : key1
secret : <BASE 64 ENCODED SECRET>
重启所有 kube-apiserver 进程。
运行下列命令使用 kms 驱动强制重新加密所有 Secret。
kubectl get secrets --all-namespaces -o json| kubectl replace -f -
禁用静态数据加密 要禁用静态数据加密:
将 identity 驱动作为配置文件中的第一个条目:
kind : EncryptionConfiguration
apiVersion : apiserver.config.k8s.io/v1
resources :
- resources :
- secrets
providers :
- identity : {}
- kms :
name : myKmsPlugin
endpoint : unix:///tmp/socketfile.sock
cachesize : 100
重启所有 kube-apiserver 进程。
运行下列命令强制重新加密所有 Secret。
kubectl get secrets --all-namespaces -o json | kubectl replace -f -
4.2.13 - 使用 Kubernetes API 访问集群 本页展示了如何使用 Kubernetes API 访问集群
准备开始
你必须拥有一个 Kubernetes 的集群,同时你的 Kubernetes 集群必须带有 kubectl 命令行工具。
如果你还没有集群,你可以通过 Minikube 构建一
个你自己的集群,或者你可以使用下面任意一个 Kubernetes 工具构建:
要获知版本信息,请输入
kubectl version.
访问集群 API 使用 kubectl 进行首次访问 首次访问 Kubernetes API 时,请使用 Kubernetes 命令行工具 kubectl 。
要访问集群,你需要知道集群位置并拥有访问它的凭证。
通常,当你完成入门指南 时,这会自动设置完成,或者由其他人设置好集群并将凭证和位置提供给你。
使用此命令检查 kubectl 已知的位置和凭证:
许多样例
提供了使用 kubectl 的介绍。完整文档请见 kubectl 手册 。
直接访问 REST API kubectl 处理对 API 服务器的定位和身份验证。如果你想通过 http 客户端(如 curl 或 wget,或浏览器)直接访问 REST API,你可以通过多种方式对 API 服务器进行定位和身份验证:
以代理模式运行 kubectl(推荐)。
推荐使用此方法,因为它用存储的 apiserver 位置并使用自签名证书验证 API 服务器的标识。
使用这种方法无法进行中间人(MITM)攻击。 另外,你可以直接为 HTTP 客户端提供位置和身份认证。
这适用于被代理混淆的客户端代码。
为防止中间人攻击,你需要将根证书导入浏览器。 使用 Go 或 Python 客户端库可以在代理模式下访问 kubectl。
使用 kubectl 代理 下列命令使 kubectl 运行在反向代理模式下。它处理 API 服务器的定位和身份认证。
像这样运行它:
kubectl proxy --port= 8080 &
参见 kubectl 代理 获取更多细节。
然后你可以通过 curl,wget,或浏览器浏览 API,像这样:
curl http://localhost:8080/api/
输出类似如下:
{
"versions" : [
"v1"
],
"serverAddressByClientCIDRs" : [
{
"clientCIDR" : "0.0.0.0/0" ,
"serverAddress" : "10.0.1.149:443"
}
]
}
不使用 kubectl 代理 通过将身份认证令牌直接传给 API 服务器,可以避免使用 kubectl 代理,像这样:
使用 grep/cut 方式:
# 查看所有的集群,因为你的 .kubeconfig 文件中可能包含多个上下文
kubectl config view -o jsonpath = '{"Cluster name\tServer\n"}{range .clusters[*]}{.name}{"\t"}{.cluster.server}{"\n"}{end}'
# 从上述命令输出中选择你要与之交互的集群的名称
export CLUSTER_NAME = "some_server_name"
# 指向引用该集群名称的 API 服务器
APISERVER = $( kubectl config view -o jsonpath = "{.clusters[?(@.name==\" $CLUSTER_NAME \")].cluster.server}" )
# 获得令牌
TOKEN = $( kubectl get secrets -o jsonpath = "{.items[?(@.metadata.annotations['kubernetes\.io/service-account\.name']=='default')].data.token}" |base64 -d)
# 使用令牌玩转 API
curl -X GET $APISERVER /api --header "Authorization: Bearer $TOKEN " --insecure
输出类似如下:
{
"kind" : "APIVersions" ,
"versions" : [
"v1"
],
"serverAddressByClientCIDRs" : [
{
"clientCIDR" : "0.0.0.0/0" ,
"serverAddress" : "10.0.1.149:443"
}
]
}
使用 jsonpath 方式:
APISERVER = $( kubectl config view --minify -o jsonpath = '{.clusters[0].cluster.server}' )
TOKEN = $( kubectl get secret $( kubectl get serviceaccount default -o jsonpath = '{.secrets[0].name}' ) -o jsonpath = '{.data.token}' | base64 --decode )
curl $APISERVER /api --header "Authorization: Bearer $TOKEN " --insecure
{
"kind" : "APIVersions" ,
"versions" : [
"v1"
],
"serverAddressByClientCIDRs" : [
{
"clientCIDR" : "0.0.0.0/0" ,
"serverAddress" : "10.0.1.149:443"
}
]
}
上面例子使用了 --insecure 标志位。这使它易受到 MITM 攻击。
当 kubectl 访问集群时,它使用存储的根证书和客户端证书访问服务器。
(已安装在 ~/.kube 目录下)。
由于集群认证通常是自签名的,因此可能需要特殊设置才能让你的 http 客户端使用根证书。
在一些集群中,API 服务器不需要身份认证;它运行在本地,或由防火墙保护着。
对此并没有一个标准。
配置对 API 的访问
讲解了作为集群管理员可如何对此进行配置。
编程方式访问 API Kubernetes 官方支持 Go 、Python 、Java 、
dotnet 、Javascript 和 Haskell
语言的客户端库。还有一些其他客户端库由对应作者而非 Kubernetes 团队提供并维护。
参考客户端库 了解如何使用其他语言
来访问 API 以及如何执行身份认证。
Go 客户端 说明: 注意 client-go 定义了自己的 API 对象,因此如果需要,请从 client-go 而不是主仓库导入
API 定义,例如 import "k8s.io/client-go/kubernetes" 是正确做法。
Go 客户端可以使用与 kubectl 命令行工具相同的
kubeconfig 文件
定位和验证 API 服务器。参见这个
例子 :
package main
import (
"context"
"fmt"
"k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/clientcmd"
)
func main () {
// uses the current context in kubeconfig
// path-to-kubeconfig -- for example, /root/.kube/config
config, _ := clientcmd.BuildConfigFromFlags ("" , "<path-to-kubeconfig>" )
// creates the clientset
clientset, _ := kubernetes.NewForConfig (config)
// access the API to list pods
pods, _ := clientset.CoreV1 ().Pods ("" ).List (context.TODO (), v1.ListOptions{})
fmt.Printf ("There are %d pods in the cluster\n" , len (pods.Items))
}
如果该应用程序部署为集群中的一个
Pod,请参阅下一节 。
Python 客户端 要使用 Python 客户端 ,运行下列命令:
pip install kubernetes。
参见 Python 客户端库主页 了解更多安装选项。
Python 客户端可以使用与 kubectl 命令行工具相同的
kubeconfig 文件
定位和验证 API 服务器。参见这个
例子 :
from kubernetes import client, config
config. load_kube_config()
v1= client. CoreV1Api()
print ("Listing pods with their IPs:" )
ret = v1. list_pod_for_all_namespaces(watch= False)
for i in ret. items:
print (" %s \t %s \t %s " % (i. status. pod_ip, i. metadata. namespace, i. metadata. name))
Java 客户端 要安装 Java 客户端 ,运行:
# 克隆 Java 库
git clone --recursive https://github.com/kubernetes-client/java
# 安装项目文件、POM 等
cd java
mvn install
参阅https://github.com/kubernetes-client/java/releases
了解当前支持的版本。
Java 客户端可以使用 kubectl 命令行所使用的
kubeconfig 文件
以定位 API 服务器并向其认证身份。
参看此示例 :
package io.kubernetes.client.examples ;
import io.kubernetes.client.ApiClient ;
import io.kubernetes.client.ApiException ;
import io.kubernetes.client.Configuration ;
import io.kubernetes.client.apis.CoreV1Api ;
import io.kubernetes.client.models.V1Pod ;
import io.kubernetes.client.models.V1PodList ;
import io.kubernetes.client.util.ClientBuilder ;
import io.kubernetes.client.util.KubeConfig ;
import java.io.FileReader ;
import java.io.IOException ;
/**
* A simple example of how to use the Java API from an application outside a kubernetes cluster
*
* <p>Easiest way to run this: mvn exec:java
* -Dexec.mainClass="io.kubernetes.client.examples.KubeConfigFileClientExample"
*
*/
public class KubeConfigFileClientExample {
public static void main ( String[] args) throws IOException, ApiException {
// file path to your KubeConfig
String kubeConfigPath = "~/.kube/config" ;
// loading the out-of-cluster config, a kubeconfig from file-system
ApiClient client =
ClientBuilder. kubeconfig ( KubeConfig. loadKubeConfig ( new FileReader( kubeConfigPath))). build ();
// set the global default api-client to the in-cluster one from above
Configuration. setDefaultApiClient ( client);
// the CoreV1Api loads default api-client from global configuration.
CoreV1Api api = new CoreV1Api();
// invokes the CoreV1Api client
V1PodList list = api. listPodForAllNamespaces ( null , null , null , null , null , null , null , null , null );
System. out . println ( "Listing all pods: " );
for ( V1Pod item : list. getItems ()) {
System. out . println ( item. getMetadata (). getName ());
}
}
}
.Net 客户端 要使用.Net 客户端 ,运行下面的命令:
dotnet add package KubernetesClient --version 1.6.1。
参见.Net 客户端库页面 了解更多安装选项。
关于可支持的版本,参见https://github.com/kubernetes-client/csharp/releases 。
.Net 客户端可以使用与 kubectl CLI 相同的 kubeconfig 文件
来定位并验证 API 服务器。
参见样例 :
using System ;
using k8s ;
namespace simple
{
internal class PodList
{
private static void Main(string [] args)
{
var config = KubernetesClientConfiguration.BuildDefaultConfig();
IKubernetes client = new Kubernetes(config);
Console.WriteLine("Starting Request!" );
var list = client.ListNamespacedPod("default" );
foreach (var item in list.Items)
{
Console.WriteLine(item.Metadata.Name);
}
if (list.Items.Count == 0 )
{
Console.WriteLine("Empty!" );
}
}
}
}
JavaScript 客户端 要安装 JavaScript 客户端 ,运行下面的命令:
npm install @kubernetes/client-node。
参考https://github.com/kubernetes-client/javascript/releases 了解可支持的版本。
JavaScript 客户端可以使用 kubectl 命令行所使用的
kubeconfig 文件
以定位 API 服务器并向其认证身份。
参见此例 :
const k8s = require('@kubernetes/client-node' );
const kc = new k8s.KubeConfig();
kc.loadFromDefault();
const k8sApi = kc.makeApiClient(k8s.CoreV1Api);
k8sApi.listNamespacedPod('default' ).then((res) => {
console.log(res.body);
});
Haskell 客户端 参考 https://github.com/kubernetes-client/haskell/releases 了解支持的版本。
Haskell 客户端
可以使用 kubectl 命令行所使用的
kubeconfig 文件
以定位 API 服务器并向其认证身份。
参见此例 :
exampleWithKubeConfig :: IO ()
exampleWithKubeConfig = do
oidcCache <- atomically $ newTVar $ Map . fromList []
(mgr, kcfg) <- mkKubeClientConfig oidcCache $ KubeConfigFile "/path/to/kubeconfig"
dispatchMime
mgr
kcfg
(CoreV1 . listPodForAllNamespaces (Accept MimeJSON ))
>>= print
接下来 4.2.14 - 保护集群安全 本文档涉及与保护集群免受意外或恶意访问有关的主题,并对总体安全性提出建议。
准备开始 控制对 Kubernetes API 的访问 因为 Kubernetes 是完全通过 API 驱动的,所以,控制和限制谁可以通过 API 访问集群,以及允许这些访问者执行什么样的 API 动作,就成为了安全控制的第一道防线。
为所有 API 交互使用传输层安全 (TLS) Kubernetes 期望集群中所有的 API 通信在默认情况下都使用 TLS 加密,大多数安装方法也允许创建所需的证书并且分发到集群组件中。请注意,某些组件和安装方法可能使用 HTTP 来访问本地端口, 管理员应该熟悉每个组件的设置,以识别潜在的不安全的流量。
API 认证 安装集群时,选择一个 API 服务器的身份验证机制,去使用与之匹配的公共访问模式。
例如,小型的单用户集群可能希望使用简单的证书或静态承载令牌方法。
更大的集群则可能希望整合现有的、OIDC、LDAP 等允许用户分组的服务器。
所有 API 客户端都必须经过身份验证,即使它是基础设施的一部分,比如节点、代理、调度程序和卷插件。
这些客户端通常使用 服务帐户
或 X509 客户端证书,并在集群启动时自动创建或是作为集群安装的一部分进行设置。
如果你希望获取更多信息,请参考认证参考文档 。
API 授权 一旦通过身份认证,每个 API 的调用都将通过鉴权检查。
Kubernetes 集成基于角色的访问控制(RBAC) 组件,
将传入的用户或组与一组绑定到角色的权限匹配。
这些权限将动作(get,create,delete)和资源(pod,service, node)在命名空间或者集群范围内结合起来,
根据客户可能希望执行的操作,提供了一组提供合理的违约责任分离的外包角色。
建议你将节点 和
RBAC 一起作为授权者,再与
NodeRestriction
准入插件结合使用。
与身份验证一样,简单而广泛的角色可能适合于较小的集群,但是随着更多的用户与集群交互,
可能需要将团队划分成有更多角色限制的单独的命名空间。
就鉴权而言,理解怎么样更新一个对象可能导致在其它地方的发生什么样的行为是非常重要的。
例如,用户可能不能直接创建 Pod,但允许他们通过创建一个 Deployment 来创建这些 Pod,
这将让他们间接创建这些 Pod。
同样地,从 API 删除一个节点将导致调度到这些节点上的 Pod 被中止,并在其他节点上重新创建。
原生的角色设计代表了灵活性和常见用例之间的平衡,但有限制的角色应该仔细审查,
以防止意外升级。如果外包角色不满足你的需求,则可以为用例指定特定的角色。
如果你希望获取更多信息,请参阅鉴权参考 。
控制对 Kubelet 的访问 Kubelet 公开 HTTPS 端点,这些端点授予节点和容器强大的控制权。
默认情况下,Kubelet 允许对此 API 进行未经身份验证的访问。
生产级别的集群应启用 Kubelet 身份验证和授权。
如果你希望获取更多信息,请参考
Kubelet 身份验证/授权参考 。
控制运行时负载或用户的能力 Kubernetes 中的授权故意设置为了高层级,它侧重于对资源的粗粒度行为。
更强大的控制是以通过用例限制这些对象如何作用于集群、自身和其他资源上的策略 存在的。
限制集群上的资源使用 资源配额
限制了授予命名空间的资源的数量或容量。
这通常用于限制命名空间可以分配的 CPU、内存或持久磁盘的数量,但也可以控制
每个命名空间中有多少个 Pod、服务或卷的存在。
限制范围 限制
上述某些资源的最大值或者最小值,以防止用户使用类似内存这样的通用保留资源时请求
不合理的过高或过低的值,或者在没有指定的情况下提供默认限制。
控制容器运行的特权 Pod 定义包含了一个安全上下文 ,
用于描述允许它请求访问某个节点上的特定 Linux 用户(如 root)、获得特权或访问主机网络、
以及允许它在主机节点上不受约束地运行的其它控件。
Pod 安全策略
可以限制哪些用户或服务帐户可以提供危险的安全上下文设置。
例如,Pod 的安全策略可以限制卷挂载,尤其是 hostpath,这些都是 Pod 应该控制的一些方面。
一般来说,大多数应用程序需要限制对主机资源的访问,
他们可以在不能访问主机信息的情况下成功以根进程(UID 0)运行。
但是,考虑到与 root 用户相关的特权,在编写应用程序容器时,你应该使用非 root 用户运行。
类似地,希望阻止客户端应用程序逃避其容器的管理员,应该使用限制性的 pod 安全策略。
限制网络访问 基于命名空间的网络策略
允许应用程序作者限制其它命名空间中的哪些 Pod 可以访问它们命名空间内的 Pod 和端口。
现在已经有许多支持网络策略的
Kubernetes 网络供应商 。
对于可以控制用户的应用程序是否在集群之外可见的许多集群,配额和限制范围也可用于
控制用户是否可以请求节点端口或负载均衡服务。
在插件或者环境基础上控制网络规则可以增加额外的保护措施,比如节点防火墙、物理分离
群集节点以防止串扰、或者高级的网络策略。
云平台(AWS, Azure, GCE 等)经常讲 metadate 本地服务暴露给实例。
默认情况下,这些 API 可由运行在实例上的 Pod 访问,并且可以包含
该云节点的凭据或配置数据(如 kubelet 凭据)。
这些凭据可以用于在集群内升级或在同一账户下升级到其他云服务。
在云平台上运行 Kubernetes 时,限制对实例凭据的权限,使用
网络策略
限制对 metadata API 的 pod 访问,并避免使用配置数据来传递机密。
控制 Pod 可以访问哪些节点 默认情况下,对哪些节点可以运行 pod 没有任何限制。
Kubernetes 给最终用户提供了
一组丰富的策略用于控制 pod 放在节点上的位置 ,
以及基于污点的 Pod 放置和驱逐 。
对于许多集群,可以约定由作者采用或者强制通过工具使用这些策略来分离工作负载。
对于管理员,Beta 阶段的准入插件 PodNodeSelector 可用于强制命名空间中的 Pod
使用默认或需要使用特定的节点选择器。
如果最终用户无法改变命名空间,这可以强烈地限制所有的 pod 在特定工作负载的位置。
保护集群组件免受破坏 本节描述保护集群免受破坏的一些常见模式。
限制访问 etcd 对于 API 来说,拥有 etcd 后端的写访问权限,相当于获得了整个集群的 root 权限,
并且可以使用写访问权限来相当快速地升级。
从 API 服务器访问它们的 etcd 服务器,管理员应该使用广受信任的凭证,
如通过 TLS 客户端证书的相互认证。
通常,我们建议将 etcd 服务器隔离到只有API服务器可以访问的防火墙后面。
注意: 允许集群中其它组件拥有读或写全空间的权限去访问 etcd 实例,相当于授予群集管理员访问的权限。
对于非主控组件,强烈推荐使用单独的 etcd 实例,或者使用 etcd 的访问控制列表
去限制只能读或者写空间的一个子集。
开启审计日志 审计日志 是 Beta 特性,
负责记录 API 操作以便在发生破坏时进行事后分析。
建议启用审计日志,并将审计文件归档到安全服务器上。
限制使用 alpha 和 beta 特性 Kubernetes 的 alpha 和 beta 特性还在努力开发中,可能存在导致安全漏洞的缺陷或错误。
要始终评估 alpha 和 beta 特性可能为你的安全态势带来的风险。
当你怀疑存在风险时,可以禁用那些不需要使用的特性。
频繁回收基础设施证书 一个 Secret 或凭据的寿命越短,攻击者就越难使用该凭据。
在证书上设置短生命周期并实现自动回收,是控制安全的一个好方法。
因此,使用身份验证提供程序时,应该要求可以控制发布令牌的可用时间,并尽可能使用短寿命。
如果在外部集成中使用服务帐户令牌,则应该频繁地回收这些令牌。
例如,一旦引导阶段完成,就应该撤销用于设置节点的引导令牌,或者取消它的授权。
在启用第三方集成之前,请先审查它们 许多集成到 Kubernetes 的第三方都可以改变你集群的安全配置。
启用集成时,在授予访问权限之前,你应该始终检查扩展所请求的权限。
例如,许多安全集成可以请求访问来查看集群上的所有 Secret,
从而有效地使该组件成为集群管理。
当有疑问时,如果可能的话,将集成限制在单个命名空间中运行。
如果组件创建的 Pod 能够在命名空间中做一些类似 kube-system 命名空间中的事情,
那么它也可能是出乎意料的强大。
因为这些 Pod 可以访问服务账户的 Secret,或者,如果这些服务帐户被授予访问许可的
Pod 安全策略 的权限,它们能以高权限运行。
对 Secret 进行静态加密 一般情况下,etcd 数据库包含了通过 Kubernetes API 可以访问到的所有信息,
并且可以授予攻击者对集群状态的可见性。
始终使用经过良好审查的备份和加密解决方案来加密备份,并考虑在可能的情况下使用全磁盘加密。
Kubernetes 1.7 包含了静态数据加密 ,
它是一个 alpha 特性,会加密 etcd 里面的 Secret 资源,以防止某一方通过查看
etcd 的备份文件查看到这些 Secret 的内容。虽然目前这还只是实验性的功能,
但是在备份没有加密或者攻击者获取到 etcd 的读访问权限的时候,它能提供额外的防御层级。
接收安全更新和报告漏洞的警报 加入 kubernetes-announce
组,能够获取有关安全公告的邮件。有关如何报告漏洞的更多信息,请参见
安全报告 页面。
4.2.15 - 关键插件 Pod 的调度保证 除了在主机上运行的 Kubernetes 核心组件(如 api-server 、scheduler 、controller-manager)之外,还有许多插件,由于各种原因,
必须在常规集群节点(而不是 Kubernetes 主节点)上运行。
其中一些插件对于功能完备的群集至关重要,例如 Heapster、DNS 和 UI。
如果关键插件被逐出(手动或作为升级等其他操作的副作用)或者变成挂起状态,群集可能会停止正常工作。
关键插件进入挂起状态的例子有:集群利用率过高;被逐出的关键插件 Pod 释放了空间,但该空间被之前悬决的 Pod 占用;由于其它原因导致节点上可用资源的总量发生变化。
标记关键 Pod 要将 pod 标记为关键性(critical),pod 必须在 kube-system 命名空间中运行(可通过参数配置)。
同时,需要将 priorityClassName 设置为 system-cluster-critical 或 system-node-critical ,后者是整个群集的最高级别。
或者,也可以为 Pod 添加名为 scheduler.alpha.kubernetes.io/critical-pod、值为空字符串的注解。
不过,这一注解从 1.13 版本开始不再推荐使用,并将在 1.14 中删除。
4.2.16 - 升级集群 本页概述升级 Kubernetes 集群的步骤。
升级集群的方式取决于你最初部署它的方式、以及后续更改它的方式。
从高层规划的角度看,要执行的步骤是:
升级控制平面 升级集群中的节点 升级 kubectl 之类的客户端 根据新 Kubernetes 版本带来的 API 变化,调整清单文件和其他资源 准备开始 你必须有一个集群。
本页内容涉及从 Kubernetes 1.23
升级到 Kubernetes 1.24。
如果你的集群未运行 Kubernetes 1.23,
那请参考目标 Kubernetes 版本的文档。
升级方法 kubeadm 如果你的集群是使用 kubeadm 安装工具部署而来,
那么升级群集的详细信息,请参阅
升级 kubeadm 集群 。
升级集群之后,要记得
安装最新版本的 kubectl .
手动部署 注意: 这些步骤不考虑第三方扩展,例如网络和存储插件。
你应该跟随下面操作顺序,手动更新控制平面:
etcd (所有实例) kube-apiserver (所有控制平面的宿主机) kube-controller-manager kube-scheduler cloud controller manager, 在你用到时 现在,你应该
安装最新版本的 kubectl .
对于群集中的每个节点,
排空
节点,然后,或者用一个运行了 1.24 kubelet 的新节点替换它;
或者升级此节点的 kubelet,并使节点恢复服务。
其他部署方式 参阅你的集群部署工具对应的文档,了解用于维护的推荐设置步骤。
升级后的任务 切换群集的存储 API 版本 对象序列化到 etcd,是为了提供集群中活动 Kubernetes 资源的内部表示法,
这些对象都使用特定版本的 API 编写。
当底层的 API 更改时,这些对象可能需要用新 API 重写。
如果不能做到这一点,会导致再也不能用 Kubernetes API 服务器解码、使用该对象。
对于每个受影响的对象,用最新支持的 API 获取它,然后再用最新支持的 API 写回来。
更新清单 升级到新版本 Kubernetes 就可以提供新的 API。
你可以使用 kubectl convert 命令在不同 API 版本之间转换清单。
例如:
kubectl convert -f pod.yaml --output-version v1
kubectl 替换了 pod.yaml 的内容,
在新的清单文件中,kind 被设置为 Pod(未变),
但 apiVersion 则被修订了。
4.2.17 - 名字空间演练 Kubernetes 名字空间
有助于不同的项目、团队或客户去共享 Kubernetes 集群。
名字空间通过以下方式实现这点:
为名字 设置作用域. 为集群中的部分资源关联鉴权和策略的机制。 使用多个名字空间是可选的。
此示例演示了如何使用 Kubernetes 名字空间细分群集。
准备开始
你必须拥有一个 Kubernetes 的集群,同时你的 Kubernetes 集群必须带有 kubectl 命令行工具。
如果你还没有集群,你可以通过 Minikube 构建一
个你自己的集群,或者你可以使用下面任意一个 Kubernetes 工具构建:
要获知版本信息,请输入
kubectl version.
环境准备 此示例作如下假设:
你已拥有一个配置好的 Kubernetes 集群 。 你已对 Kubernetes 的 Pods 、
Services 和
Deployments
有基本理解。 理解默认名字空间 默认情况下,Kubernetes 集群会在配置集群时实例化一个默认名字空间,用以存放集群所使用的默认
Pod、Service 和 Deployment 集合。
假设你有一个新的集群,你可以通过执行以下操作来检查可用的名字空间:
NAME STATUS AGE
default Active 13m
创建新的名字空间 在本练习中,我们将创建两个额外的 Kubernetes 名字空间来保存我们的内容。
我们假设一个场景,某组织正在使用共享的 Kubernetes 集群来支持开发和生产:
开发团队希望在集群中维护一个空间,以便他们可以查看用于构建和运行其应用程序的 Pod、Service
和 Deployment 列表。在这个空间里,Kubernetes 资源被自由地加入或移除,
对谁能够或不能修改资源的限制被放宽,以实现敏捷开发。
运维团队希望在集群中维护一个空间,以便他们可以强制实施一些严格的规程,
对谁可以或谁不可以操作运行生产站点的 Pod、Service 和 Deployment 集合进行控制。
该组织可以遵循的一种模式是将 Kubernetes 集群划分为两个名字空间:development 和 production。
让我们创建两个新的名字空间来保存我们的工作。
文件 namespace-dev.json 描述了 development 名字空间:
{
"apiVersion" : "v1" ,
"kind" : "Namespace" ,
"metadata" : {
"name" : "development" ,
"labels" : {
"name" : "development"
}
}
}
使用 kubectl 创建 development 名字空间。
kubectl create -f https://k8s.io/examples/admin/namespace-dev.json
将下列的内容保存到文件 namespace-prod.json 中,
这些内容是对 production 名字空间的描述:
{
"apiVersion" : "v1" ,
"kind" : "Namespace" ,
"metadata" : {
"name" : "production" ,
"labels" : {
"name" : "production"
}
}
}
让我们使用 kubectl 创建 production 名字空间。
kubectl create -f https://k8s.io/examples/admin/namespace-prod.json
为了确保一切正常,我们列出集群中的所有名字空间。
kubectl get namespaces --show-labels
NAME STATUS AGE LABELS
default Active 32m <none>
development Active 29s name=development
production Active 23s name=production
在每个名字空间中创建 pod Kubernetes 名字空间为集群中的 Pod、Service 和 Deployment 提供了作用域。
与一个名字空间交互的用户不会看到另一个名字空间中的内容。
为了演示这一点,让我们在 development 名字空间中启动一个简单的 Deployment 和 Pod。
我们首先检查一下当前的上下文:
apiVersion : v1
clusters :
- cluster :
certificate-authority-data : REDACTED
server : https://130.211.122.180
name : lithe-cocoa-92103_kubernetes
contexts :
- context :
cluster : lithe-cocoa-92103_kubernetes
user : lithe-cocoa-92103_kubernetes
name : lithe-cocoa-92103_kubernetes
current-context : lithe-cocoa-92103_kubernetes
kind : Config
preferences : {}
users :
- name : lithe-cocoa-92103_kubernetes
user :
client-certificate-data : REDACTED
client-key-data : REDACTED
token : 65rZW78y8HbwXXtSXuUw9DbP4FLjHi4b
- name : lithe-cocoa-92103_kubernetes-basic-auth
user :
password : h5M0FtUUIflBSdI7
username : admin
kubectl config current-context
lithe-cocoa-92103_kubernetes
下一步是为 kubectl 客户端定义一个上下文,以便在每个名字空间中工作。
"cluster" 和 "user" 字段的值将从当前上下文中复制。
kubectl config set-context dev --namespace= development \
--cluster= lithe-cocoa-92103_kubernetes \
--user= lithe-cocoa-92103_kubernetes
kubectl config set-context prod --namespace= production \
--cluster= lithe-cocoa-92103_kubernetes \
--user= lithe-cocoa-92103_kubernetes
默认情况下,上述命令会添加两个上下文到 .kube/config 文件中。
你现在可以查看上下文并根据你希望使用的名字空间并在这两个新的请求上下文之间切换。
查看新的上下文:
apiVersion : v1
clusters :
- cluster :
certificate-authority-data : REDACTED
server : https://130.211.122.180
name : lithe-cocoa-92103_kubernetes
contexts :
- context :
cluster : lithe-cocoa-92103_kubernetes
user : lithe-cocoa-92103_kubernetes
name : lithe-cocoa-92103_kubernetes
- context :
cluster : lithe-cocoa-92103_kubernetes
namespace : development
user : lithe-cocoa-92103_kubernetes
name : dev
- context :
cluster : lithe-cocoa-92103_kubernetes
namespace : production
user : lithe-cocoa-92103_kubernetes
name : prod
current-context : lithe-cocoa-92103_kubernetes
kind : Config
preferences : {}
users :
- name : lithe-cocoa-92103_kubernetes
user :
client-certificate-data : REDACTED
client-key-data : REDACTED
token : 65rZW78y8HbwXXtSXuUw9DbP4FLjHi4b
- name : lithe-cocoa-92103_kubernetes-basic-auth
user :
password : h5M0FtUUIflBSdI7
username : admin
让我们切换到 development 名字空间进行操作。
kubectl config use-context dev
你可以使用下列命令验证当前上下文:
kubectl config current-context
dev
此时,我们从命令行向 Kubernetes 集群发出的所有请求都限定在 development 名字空间中。
让我们创建一些内容。
apiVersion : apps/v1
kind : Deployment
metadata :
labels :
app : snowflake
name : snowflake
spec :
replicas : 2
selector :
matchLabels :
app : snowflake
template :
metadata :
labels :
app : snowflake
spec :
containers :
- image : k8s.gcr.io/serve_hostname
imagePullPolicy : Always
name : snowflake
应用清单文件来创建 Deployment。
我们刚刚创建了一个副本大小为 2 的 Deployment,该 Deployment 运行名为 snowflake 的 Pod,
其中包含一个仅提供主机名服务的基本容器。
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
snowflake 2 2 2 2 2m
kubectl get pods -l app = snowflake
NAME READY STATUS RESTARTS AGE
snowflake-3968820950-9dgr8 1/1 Running 0 2m
snowflake-3968820950-vgc4n 1/1 Running 0 2m
这很棒,开发人员可以做他们想要的事情,而不必担心影响 production 名字空间中的内容。
让我们切换到 production 名字空间,展示一个名字空间中的资源如何对另一个名字空间不可见。
kubectl config use-context prod
production 名字空间应该是空的,下列命令应该返回的内容为空。
kubectl get deployment
kubectl get pods
生产环境需要以放牛的方式运维,让我们创建一些名为 cattle 的 Pod。
kubectl create deployment cattle --image= k8s.gcr.io/serve_hostname --replicas= 5
kubectl get deployment
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
cattle 5 5 5 5 10s
kubectl get pods -l run = cattle
NAME READY STATUS RESTARTS AGE
cattle-2263376956-41xy6 1/1 Running 0 34s
cattle-2263376956-kw466 1/1 Running 0 34s
cattle-2263376956-n4v97 1/1 Running 0 34s
cattle-2263376956-p5p3i 1/1 Running 0 34s
cattle-2263376956-sxpth 1/1 Running 0 34s
此时,应该很清楚的展示了用户在一个名字空间中创建的资源对另一个名字空间是不可见的。
随着 Kubernetes 中的策略支持的发展,我们将扩展此场景,以展示如何为每个名字空间提供不同的授权规则。
4.2.18 - 启用 EndpointSlices 本页提供启用 Kubernetes EndpointSlice 的总览。
准备开始
你必须拥有一个 Kubernetes 的集群,同时你的 Kubernetes 集群必须带有 kubectl 命令行工具。
如果你还没有集群,你可以通过 Minikube 构建一
个你自己的集群,或者你可以使用下面任意一个 Kubernetes 工具构建:
要获知版本信息,请输入
kubectl version.
介绍 EndpointSlice (端点切片)为 Kubernetes Endpoints 提供了可伸缩和可扩展的替代方案。
它们建立在 Endpoints 提供的功能基础之上,并以可伸缩的方式进行扩展。
当 Service 具有大量(>100)网络端点时,它们将被分成多个较小的 EndpointSlice 资源,
而不是单个大型 Endpoints 资源。
启用 EndpointSlice FEATURE STATE: Kubernetes v1.17 [beta]
说明: EndpointSlice 资源旨在解决较早资源:Endpoints 中的缺点。一些 Kubernetes 组件和第三方应用程序
继续使用并依赖 Endpoints。既然情况如此,应该将 EndpointSlices 视为集群中 Endpoints 的补充,而不是
彻底替代。
Kubernetes 中的 EndpointSlice 功能包含若干不同组件。它们中的大部分都是
默认被启用的:
EndpointSlice API :EndpointSlice 隶属于 discovery.k8s.io/v1beta1 API。
此 API 处于 Beta 阶段,从 Kubernetes 1.17 开始默认被启用。
下面列举的所有组件都依赖于此 API 被启用。EndpointSlice 控制器 :此 控制器
为 Service 维护 EndpointSlice 及其引用的 Pods。
此控制器通过 EndpointSlice 特性门控控制。自从 Kubernetes 1.18 起,
该特性门控默认被启用。EndpointSliceMirroring 控制器 :此 控制器
将自定义的 Endpoints 映射为 EndpointSlice。
控制器受 EndpointSlice 特性门控控制。该特性门控自 1.19 开始被默认启用。kube-proxy :当 kube-proxy
被配置为使用 EndpointSlice 时,它会支持更大数量的 Service 端点。
此功能在 Linux 上受 EndpointSliceProxying 特性门控控制;在 Windows 上受
WindowsEndpointSliceProxying 特性门控控制。
在 Linux 上,从 Kubernetes 1.19 版本起自动启用。目前尚未在 Windows 节点
上默认启用。
要在 Windows 节点上配置 kube-proxy 使用 EndpointSlice,你需要为 kube-proxy 启用
WindowsEndpointSliceProxying
特性门控 。API 字段 EndpointSlice API 中的某些字段有对应的特性门控控制。
EndpointSliceNodeName 特性门控控制对 nodeName 字段的访问。这是默认情况下禁用的 Alpha 功能。EndpointSliceTerminating 特性门控控制对 serving 和 terminating 状况字段的访问。这是默认情况下禁用的 Alpha 功能。使用 EndpointSlice 在集群中完全启用 EndpointSlice 的情况下,你应该看到对应于每个
Endpoints 资源的 EndpointSlice 资源。除了支持现有的 Endpoints 功能外,
EndpointSlices 将允许集群中网络端点更好的可伸缩性和可扩展性。
接下来 4.2.19 - 启用/禁用 Kubernetes API 本页展示怎么用集群的
控制平面 .
启用/禁用 API 版本。
通过 API 服务器的命令行参数 --runtime-config=api/<version> ,
可以开启/关闭某个指定的 API 版本。
此参数的值是一个逗号分隔的 API 版本列表。
此列表中,后面的值可以覆盖前面的值。
命令行参数 runtime-config 支持两个特殊的值(keys):
api/all:指所有已知的 APIapi/legacy:指过时的 API。过时的 API 就是明确地
弃用
的 API。例如:为了停用除去 v1 版本之外的全部其他 API 版本,
就用参数 --runtime-config=api/all=false,api/v1=true 启动 kube-apiserver。
接下来 阅读完整的文档 ,
以了解 kube-apiserver 组件。
4.2.20 - 在 Kubernetes 集群中使用 NodeLocal DNSCache FEATURE STATE: Kubernetes v1.18 [stable]
本页概述了 Kubernetes 中的 NodeLocal DNSCache 功能。
准备开始
你必须拥有一个 Kubernetes 的集群,同时你的 Kubernetes 集群必须带有 kubectl 命令行工具。
如果你还没有集群,你可以通过 Minikube 构建一
个你自己的集群,或者你可以使用下面任意一个 Kubernetes 工具构建:
要获知版本信息,请输入
kubectl version.
引言 NodeLocal DNSCache 通过在集群节点上作为 DaemonSet 运行 dns 缓存代理来提高集群 DNS 性能。
在当今的体系结构中,处于 ClusterFirst DNS 模式的 Pod 可以连接到 kube-dns serviceIP 进行 DNS 查询。
通过 kube-proxy 添加的 iptables 规则将其转换为 kube-dns/CoreDNS 端点。
借助这种新架构,Pods 将可以访问在同一节点上运行的 dns 缓存代理,从而避免了 iptables DNAT 规则和连接跟踪。
本地缓存代理将查询 kube-dns 服务以获取集群主机名的缓存缺失(默认为 cluster.local 后缀)。
动机 使用当前的 DNS 体系结构,如果没有本地 kube-dns/CoreDNS 实例,则具有最高 DNS QPS 的 Pod 可能必须延伸到另一个节点。
在这种脚本下,拥有本地缓存将有助于改善延迟。 跳过 iptables DNAT 和连接跟踪将有助于减少 conntrack 竞争 并避免 UDP DNS 条目填满 conntrack 表。 从本地缓存代理到 kube-dns 服务的连接可以升级到 TCP 。
TCP conntrack 条目将在连接关闭时被删除,相反 UDP 条目必须超时(默认 nf_conntrack_udp_timeout 是 30 秒) 将 DNS 查询从 UDP 升级到 TCP 将减少归因于丢弃的 UDP 数据包和 DNS 超时的尾部等待时间,通常长达 30 秒(3 次重试+ 10 秒超时)。 可以重新启用负缓存,从而减少对 kube-dns 服务的查询数量。 架构图 启用 NodeLocal DNSCache 之后,这是 DNS 查询所遵循的路径:
Nodelocal DNSCache 流 此图显示了 NodeLocal DNSCache 如何处理 DNS 查询。
配置 说明: NodeLocal DNSCache 的本地侦听 IP 地址可以是任何地址,只要该地址不和你的集群里现有的 IP 地址发生冲突。
推荐使用本地范围内的地址,例如,IPv4 链路本地区段 169.254.0.0/16 内的地址,
或者 IPv6 唯一本地地址区段 fd00::/8 内的地址。
可以使用以下步骤启动此功能:
如果使用 IPv6,在使用 IP:Port 格式的时候需要把 CoreDNS 配置文件里的所有 IPv6 地址用方括号包起来。
如果你使用上述的示例清单,需要把 配置行 L70
修改为 health [__PILLAR__LOCAL__DNS__]:8080。 如果 kube-proxy 运行在 IPTABLES 模式:
sed -i "s/__PILLAR__LOCAL__DNS__/ $localdns /g; s/__PILLAR__DNS__DOMAIN__/ $domain /g; s/__PILLAR__DNS__SERVER__/ $kubedns /g" nodelocaldns.yaml
node-local-dns Pods 会设置 __PILLAR__CLUSTER__DNS__ 和 __PILLAR__UPSTREAM__SERVERS__。
在此模式下, node-local-dns Pods 会同时侦听 kube-dns 服务的 IP 地址和 <node-local-address> 的地址,
以便 Pods 可以使用其中任何一个 IP 地址来查询 DNS 记录。
如果 kube-proxy 运行在 IPVS 模式:
sed -i "s/__PILLAR__LOCAL__DNS__/ $localdns /g; s/__PILLAR__DNS__DOMAIN__/ $domain /g; s/__PILLAR__DNS__SERVER__//g; s/__PILLAR__CLUSTER__DNS__/ $kubedns /g" nodelocaldns.yaml
在此模式下,node-local-dns Pods 只会侦听 <node-local-address> 的地址。
node-local-dns 接口不能绑定 kube-dns 的集群 IP 地址,因为 IPVS 负载均衡
使用的接口已经占用了该地址。
node-local-dns Pods 会设置 __PILLAR__UPSTREAM__SERVERS__。
运行 kubectl create -f nodelocaldns.yaml 如果 kube-proxy 运行在 IPVS 模式,需要修改 kubelet 的 --cluster-dns 参数为 NodeLocal DNSCache 正在侦听的 <node-local-address> 地址。
否则,不需要修改 --cluster-dns 参数,因为 NodeLocal DNSCache 会同时侦听 kube-dns 服务的 IP 地址和 <node-local-address> 的地址。 启用后,node-local-dns Pods 将在每个集群节点上的 kube-system 名字空间中运行。
此 Pod 在缓存模式下运行 CoreDNS ,因此每个节点都可以使用不同插件公开的所有 CoreDNS 指标。
如果要禁用该功能,你可以使用 kubectl delete -f <manifest> 来删除 DaemonSet。你还应该恢复你对 kubelet 配置所做的所有改动。
4.2.21 - 在 Kubernetes 集群中使用 sysctl FEATURE STATE: Kubernetes v1.12 [beta]
本文档介绍如何通过 sysctl
接口在 Kubernetes 集群中配置和使用内核参数。
准备开始
你必须拥有一个 Kubernetes 的集群,同时你的 Kubernetes 集群必须带有 kubectl 命令行工具。
如果你还没有集群,你可以通过 Minikube 构建一
个你自己的集群,或者你可以使用下面任意一个 Kubernetes 工具构建:
要获知版本信息,请输入
kubectl version.
获取 Sysctl 的参数列表 在 Linux 中,管理员可以通过 sysctl 接口修改内核运行时的参数。在 /proc/sys/
虚拟文件系统下存放许多内核参数。这些参数涉及了多个内核子系统,如:
内核子系统(通常前缀为: kernel.) 网络子系统(通常前缀为: net.) 虚拟内存子系统(通常前缀为: vm.) MDADM 子系统(通常前缀为: dev.) 更多子系统请参见内核文档 。 若要获取完整的参数列表,请执行以下命令
启用非安全的 Sysctl 参数 sysctl 参数分为 安全 和 非安全的 。
安全 sysctl 参数除了需要设置恰当的命名空间外,在同一 node 上的不同 Pod
之间也必须是 相互隔离的 。这意味着在 Pod 上设置 安全 sysctl 参数
必须不能影响到节点上的其他 Pod 必须不能损害节点的健康 必须不允许使用超出 Pod 的资源限制的 CPU 或内存资源。 至今为止,大多数 有命名空间的 sysctl 参数不一定被认为是 安全 的。
以下几种 sysctl 参数是 安全的 :
kernel.shm_rmid_forcednet.ipv4.ip_local_port_rangenet.ipv4.tcp_syncookiesnet.ipv4.ping_group_range (从 Kubernetes 1.18 开始)说明: 示例中的 net.ipv4.tcp_syncookies 在Linux 内核 4.4 或更低的版本中是无命名空间的。
在未来的 Kubernetes 版本中,若 kubelet 支持更好的隔离机制,则上述列表中将会
列出更多 安全的 sysctl 参数。
所有 安全的 sysctl 参数都默认启用。
所有 非安全的 sysctl 参数都默认禁用,且必须由集群管理员在每个节点上手动开启。
那些设置了不安全 sysctl 参数的 Pod 仍会被调度,但无法正常启动。
参考上述警告,集群管理员只有在一些非常特殊的情况下(如:高可用或实时应用调整),
才可以启用特定的 非安全的 sysctl 参数。
如需启用 非安全的 sysctl 参数,请你在每个节点上分别设置 kubelet 命令行参数,例如:
kubelet --allowed-unsafe-sysctls \
'kernel.msg*,net.core.somaxconn' ...
如果你使用 Minikube ,可以通过 extra-config 参数来配置:
minikube start --extra-config= "kubelet.allowed-unsafe-sysctls=kernel.msg*,net.core.somaxconn" ...
只有 有命名空间的 sysctl 参数可以通过该方式启用。
设置 Pod 的 Sysctl 参数 目前,在 Linux 内核中,有许多的 sysctl 参数都是 有命名空间的 。
这就意味着可以为节点上的每个 Pod 分别去设置它们的 sysctl 参数。
在 Kubernetes 中,只有那些有命名空间的 sysctl 参数可以通过 Pod 的 securityContext 对其进行配置。
以下列出有命名空间的 sysctl 参数,在未来的 Linux 内核版本中,此列表可能会发生变化。
kernel.shm*,kernel.msg*,kernel.sem,fs.mqueue.*,net.*(内核中可以在容器命名空间里被更改的网络配置项相关参数)。然而也有一些特例
(例如,net.netfilter.nf_conntrack_max 和 net.netfilter.nf_conntrack_expect_max
可以在容器命名空间里被更改,但它们是非命名空间的)。没有命名空间的 sysctl 参数称为 节点级别的 sysctl 参数。
如果需要对其进行设置,则必须在每个节点的操作系统上手动地去配置它们,
或者通过在 DaemonSet 中运行特权模式容器来配置。
可使用 Pod 的 securityContext 来配置有命名空间的 sysctl 参数,
securityContext 应用于同一个 Pod 中的所有容器。
此示例中,使用 Pod SecurityContext 来对一个安全的 sysctl 参数
kernel.shm_rmid_forced 以及两个非安全的 sysctl 参数
net.core.somaxconn 和 kernel.msgmax 进行设置。
在 Pod 规约中对 安全的 和 非安全的 sysctl 参数不做区分。
警告: 为了避免破坏操作系统的稳定性,请你在了解变更后果之后再修改 sysctl 参数。
apiVersion : v1
kind : Pod
metadata :
name : sysctl-example
spec :
securityContext :
sysctls :
- name : kernel.shm_rmid_forced
value : "0"
- name : net.core.somaxconn
value : "1024"
- name : kernel.msgmax
value : "65536"
...
警告: 由于 非安全的 sysctl 参数其本身具有不稳定性,在使用 非安全的 sysctl 参数
时可能会导致一些严重问题,如容器的错误行为、机器资源不足或节点被完全破坏,
用户需自行承担风险。
最佳实践方案是将集群中具有特殊 sysctl 设置的节点视为 有污点的 ,并且只调度
需要使用到特殊 sysctl 设置的 Pod 到这些节点上。
建议使用 Kubernetes 的
污点和容忍度特性 来实现它。
设置了 非安全的 sysctl 参数的 Pod 在禁用了这两种 非安全的 sysctl 参数配置
的节点上启动都会失败。与 节点级别的 sysctl 一样,建议开启
污点和容忍度特性 或
为节点配置污点
以便将 Pod 调度到正确的节点之上。
PodSecurityPolicy 你可以通过在 PodSecurityPolicy 的 forbiddenSysctls 和/或 allowedUnsafeSysctls
字段中,指定 sysctl 或填写 sysctl 匹配模式来进一步为 Pod 设置 sysctl 参数。
sysctl 参数匹配模式以 * 字符结尾,如 kernel.*。
单独的 * 字符匹配所有 sysctl 参数。
所有 安全的 sysctl 参数都默认启用。
forbiddenSysctls 和 allowedUnsafeSysctls 的值都是字符串列表类型,
可以添加 sysctl 参数名称,也可以添加 sysctl 参数匹配模式(以*结尾)。
只填写 * 则匹配所有的 sysctl 参数。
forbiddenSysctls 字段用于禁用特定的 sysctl 参数。
你可以在列表中禁用安全和非安全的 sysctl 参数的组合。
要禁用所有的 sysctl 参数,请设置为 *。
如果要在 allowedUnsafeSysctls 字段中指定一个非安全的 sysctl 参数,
并且它在 forbiddenSysctls 字段中未被禁用,则可以在 Pod 中通过
PodSecurityPolicy 启用该 sysctl 参数。
若要在 PodSecurityPolicy 中开启所有非安全的 sysctl 参数,
请设 allowedUnsafeSysctls 字段值为 *。
allowedUnsafeSysctls 与 forbiddenSysctls 两字段的配置不能重叠,
否则这就意味着存在某个 sysctl 参数既被启用又被禁用。
警告: 如果你通过 PodSecurityPolicy 中的 allowedUnsafeSysctls 字段将非安全的 sysctl
参数列入白名单,但该 sysctl 参数未通过 kubelet 命令行参数
--allowed-unsafe-sysctls 在节点上将其列入白名单,则设置了这个 sysctl
参数的 Pod 将会启动失败。
以下示例设置启用了以 kernel.msg 为前缀的非安全的 sysctl 参数,同时禁用了
sysctl 参数 kernel.shm_rmid_forced。
apiVersion : policy/v1beta1
kind : PodSecurityPolicy
metadata :
name : sysctl-psp
spec :
allowedUnsafeSysctls :
- kernel.msg*
forbiddenSysctls :
- kernel.shm_rmid_forced
...
4.2.22 - 在运行中的集群上重新配置节点的 kubelet FEATURE STATE: Kubernetes v1.11 [beta]
动态 kubelet 配置
允许你在一个运行的 Kubernetes 集群上通过部署 ConfigMap
并配置每个节点来使用它来更改每个 kubelet 的配置,。
警告: 所有 kubelet 配置参数都可以动态更改,但这对某些参数来说是不安全的。
在决定动态更改参数之前,你需要深刻理解这种变化将如何影响你的集群的行为。
在把一组变更推广到集群范围之前,需要在较小规模的节点集合上仔细地测试这些配置变化。
与特定字段配置相关的建议可以在源码中
KubeletConfiguration
类型文档 中找到。
准备开始 你需要一个 Kubernetes 集群。
你需要 v1.11 或更高版本的 kubectl,并以配置好与集群通信。
要获知版本信息,请输入 kubectl version.
你的集群 API 服务器版本(如 v1.12)不能比你所用的 kubectl
的版本差不止一个小版本号。
例如,如果你的集群在运行 v1.16,那么你可以使用 v1.15、v1.16、v1.17 的 kubectl,
所有其他的组合都是
不支持的 。
某些例子中使用了命令行工具 jq 。
你并不一定需要 jq 才能完成这些任务,因为总是有一些手工替代的方式。
针对你所重新配置的每个节点,你必须设置 kubelet 的参数
-dynamic-config-dir,使之指向一个可写的目录。
重配置 集群中运行节点上的 kubelet 基本工作流程概述 在运行中的集群中配置 kubelet 的基本工作流程如下:
编写一个 YAML 或 JSON 的配置文件包含 kubelet 的配置。 将此文件包装在 ConfigMap 中并将其保存到 Kubernetes 控制平面。 更新 kubelet 的相应节点对象以使用此 ConfigMap。 每个 kubelet 都会在其各自的节点对象上监测(Watch)配置引用。当引用更改时,kubelet 将下载新配置,
更新本地引用以引用该文件,然后退出。
要想使该功能正常地工作,你必须运行操作系统级别的服务管理器(如 systemd),
在 kubelet 退出时将其重启。
kubelet 重新启动时,将开始使用新配置。
这个新配置完全地覆盖 --config 所提供的配置,并被命令行标志覆盖。
新配置中未指定的值将收到适合配置版本的默认值
(e.g. kubelet.config.k8s.io/v1beta1),除非被命令行标志覆盖。
节点 kubelet 配置状态可通过 node.spec.status.config 获取。
一旦你已经改变了一个节点去使用新的 ConfigMap,
就可以观察此状态以确认该节点正在使用的预期配置。
本文用命令 kubectl edit 描述节点的编辑,还有一些其他的方式去修改节点的规约,
包括更利于脚本化的工作流程的 kubectl patch。
本文仅仅讲述在单节点上使用每个 ConfigMap。请注意对于多个节点使用相同的 ConfigMap
也是合法的。
警告: 通过就地更新 ConfigMap 来更改配置是 可能的 。
尽管如此,这样做会导致所有配置为使用该 ConfigMap 的 kubelet 被同时更新。
更安全的做法是按惯例将 ConfigMap 视为不可变更的,借助于
kubectl 的 --append-hash 选项逐步把更新推广到 node.spec.configSource。
节点鉴权器的自动 RBAC 规则 以前,你需要手动创建 RBAC 规则以允许节点访问其分配的 ConfigMap。节点鉴权器现在
能够自动配置这些规则。
生成包含当前配置的文件 动态 kubelet 配置特性允许你为整个配置对象提供一个重载配置,而不是靠单个字段的叠加。
这是一个更简单的模型,可以更轻松地跟踪配置值的来源,更便于调试问题。
然而,相应的代价是你必须首先了解现有配置,以确保你只更改你打算修改的字段。
组件 kubelet 从其配置文件中加载配置数据,不过你可以通过设置命令行标志
来重载文件中的一些配置。这意味着,如果你仅知道配置文件的内容,而你不知道
命令行重载了哪些配置,你就无法知道 kubelet 的运行时配置是什么。
因为你需要知道运行时所使用的配置才能重载之,你可以从 kubelet 取回其运行时配置。
你可以通过访问 kubelet 的 configz 末端来生成包含节点当前配置的配置文件;
这一操作可以通过 kubectl proxy 来完成。
下一节解释如何完成这一操作。
注意: 组件 kubelet 上的 configz 末端是用来协助调试的,并非 kubelet 稳定行为的一部分。
请不要在产品环境下依赖此末端的行为,也不要在自动化工具中使用此末端。
关于如何使用配置文件来配置 kubelet 行为的更多信息可参见
通过配置文件设置 kubelet 参数
文档。
生成配置文件 说明: 下面的任务步骤中使用了 jq 命令以方便处理 JSON 数据。为了完成这里讲述的任务,
你需要安装 jq。如果你更希望手动提取 kubeletconfig 子对象,也可以对这里
的对应步骤做一些调整。
选择要重新配置的节点。在本例中,此节点的名称为 NODE_NAME。
使用以下命令在后台启动 kubectl 代理:
kubectl proxy --port= 8001 &
运行以下命令从 configz 端点中下载并解压配置。这个命令很长,因此在复制粘贴时要小心。
如果你使用 zsh ,请注意常见的 zsh 配置要添加反斜杠转义 URL 中变量名称周围的大括号。
例如:在粘贴时,${NODE_NAME} 将被重写为 $\{NODE_NAME\}。
你必须在运行命令之前删除反斜杠,否则命令将失败。
NODE_NAME = "the-name-of-the-node-you-are-reconfiguring" ; curl -sSL "http://localhost:8001/api/v1/nodes/ ${ NODE_NAME } /proxy/configz" | jq '.kubeletconfig|.kind="KubeletConfiguration"|.apiVersion="kubelet.config.k8s.io/v1beta1"' > kubelet_configz_${ NODE_NAME }
说明: 你需要手动将 kind 和 apiVersion 添加到下载对象中,因为它们不是由 configz 末端
返回的。
修改配置文件 使用文本编辑器,改变上述操作生成的文件中一个参数。
例如,你或许会修改 QPS 参数 eventRecordQPS。
把配置文件推送到控制平面 用以下命令把编辑后的配置文件推送到控制平面:
kubectl -n kube-system create configmap my-node-config \
--from-file= kubelet = kubelet_configz_${ NODE_NAME } \
--append-hash -o yaml
下面是合法响应的一个例子:
apiVersion : v1
kind : ConfigMap
metadata :
creationTimestamp : 2017-09-14T20:23:33Z
name : my-node-config-gkt4c2m4b2
namespace : kube-system
resourceVersion : "119980"
selfLink : /api/v1/namespaces/kube-system/configmaps/my-node-config-gkt4c2m4b2
uid : 946d785e-998a-11e7-a8dd-42010a800006
data :
kubelet : |
{...}
你会在 kube-system 命名空间中创建 ConfigMap,因为 kubelet 是 Kubernetes 的系统组件。
--append-hash 选项给 ConfigMap 内容附加了一个简短校验和。
这对于先编辑后推送的工作流程很方便,
因为它自动并确定地为新 ConfigMap 生成新的名称。
在以下示例中,包含生成的哈希字符串的对象名被称为 CONFIG_MAP_NAME。
配置节点使用新的配置 kubectl edit node ${ NODE_NAME }
在你的文本编辑器中,在 spec 下增添以下 YAML:
configSource :
configMap :
name : CONFIG_MAP_NAME
namespace : kube-system
kubeletConfigKey : kubelet
你必须同时指定 name、namespace 和 kubeletConfigKey 这三个属性。
kubeletConfigKey 这个参数通知 kubelet ConfigMap 中的哪个键下面包含所要的配置。
观察节点开始使用新配置 用 kubectl get node ${NODE_NAME} -o yaml 命令读取节点并检查 node.status.config 内容。
状态部分报告了对应 active(使用中的)配置、assigned(被赋予的)配置和
lastKnownGood(最近已知可用的)配置的配置源。
active 是 kubelet 当前运行时所使用的版本。assigned 参数是 kubelet 基于 node.spec.configSource 所解析出来的最新版本。lastKnownGood 参数是 kubelet 的回退版本;如果在 node.spec.configSource 中
包含了无效的配置值,kubelet 可以回退到这个版本。如果用本地配置部署节点,使其设置成默认值,这个 lastKnownGood 配置可能不存在。
在 kubelet 配置好后,将更新 lastKnownGood 为一个有效的 assigned 配置。
决定如何确定某配置成为 lastKnownGood 配置的细节并不在 API 保障范畴,
不过目前实现中采用了 10 分钟的宽限期。
你可以使用以下命令(使用 jq)过滤出配置状态:
kubectl get no ${ NODE_NAME } -o json | jq '.status.config'
以下是一个响应示例:
{
"active" : {
"configMap" : {
"kubeletConfigKey" : "kubelet" ,
"name" : "my-node-config-9mbkccg2cc" ,
"namespace" : "kube-system" ,
"resourceVersion" : "1326" ,
"uid" : "705ab4f5-6393-11e8-b7cc-42010a800002"
}
},
"assigned" : {
"configMap" : {
"kubeletConfigKey" : "kubelet" ,
"name" : "my-node-config-9mbkccg2cc" ,
"namespace" : "kube-system" ,
"resourceVersion" : "1326" ,
"uid" : "705ab4f5-6393-11e8-b7cc-42010a800002"
}
},
"lastKnownGood" : {
"configMap" : {
"kubeletConfigKey" : "kubelet" ,
"name" : "my-node-config-9mbkccg2cc" ,
"namespace" : "kube-system" ,
"resourceVersion" : "1326" ,
"uid" : "705ab4f5-6393-11e8-b7cc-42010a800002"
}
}
}
如果你没有安装 jq,你可以查看整个响应对象,查找其中的 node.status.config
部分。
如果发生错误,kubelet 会在 node.status.config.error 中显示出错误信息的结构体。
可能的错误列在了解节点配置错误信息 节。
你可以在 kubelet 日志中搜索相同的文本以获取更多详细信息和有关错误的上下文。
做出更多的改变 按照下面的工作流程做出更多的改变并再次推送它们。
你每次推送一个 ConfigMap 的新内容时,kubeclt 的 --append-hash 选项都会给
ConfigMap 创建一个新的名称。
最安全的上线策略是首先创建一个新的 ConfigMap,然后更新节点以使用新的 ConfigMap。
重置节点以使用其本地默认配置 要重置节点,使其使用节点创建时使用的配置,可以用
kubectl edit node $ {NODE_NAME} 命令编辑节点,并删除 node.spec.configSource
字段。
观察节点正在使用本地默认配置 在删除此字段后,node.status.config 最终变成空,所有配置源都已重置为 nil。
这表示本地默认配置成为了 assigned、active 和 lastKnownGood 配置,
并且没有报告错误。
kubectl patch 示例你可以使用几种不同的机制来更改节点的 configSource。
本例使用kubectl patch:
kubectl patch node ${ NODE_NAME } -p "{\"spec\":{\"configSource\":{\"configMap\":{\"name\":\" ${ CONFIG_MAP_NAME } \",\"namespace\":\"kube-system\",\"kubeletConfigKey\":\"kubelet\"}}}}"
了解 Kubelet 如何为配置生成检查点 当为节点赋予新配置时,kubelet 会下载并解压配置负载为本地磁盘上的一组文件。
kubelet 还记录一些元数据,用以在本地跟踪已赋予的和最近已知良好的配置源,以便
kubelet 在重新启动时知道使用哪个配置,即使 API 服务器变为不可用。
在为配置信息和相关元数据生成检查点之后,如果检测到已赋予的配置发生改变,则 kubelet 退出。
当 kubelet 被 OS 级服务管理器(例如 systemd)重新启动时,它会读取新的元数据并使用新配置。
当记录的元数据已被完全解析时,意味着它包含选择一个指定的配置版本所需的所有信息
-- 通常是 UID 和 ResourceVersion。
这与 node.spec.configSource 形成对比,后者通过幂等的 namespace/name 声明来标识
目标 ConfigMap;kubelet 尝试使用此 ConfigMap 的最新版本。
当你在调试节点上问题时,可以检查 kubelet 的配置元数据和检查点。kubelet 的检查点目录结构是:
- --dynamic-config-dir (用于管理动态配置的根目录)
|-- meta
| - assigned (编码后的 kubeletconfig/v1beta1.SerializedNodeConfigSource 对象,对应赋予的配置)
| - last-known-good (编码后的 kubeletconfig/v1beta1.SerializedNodeConfigSource 对象,对应最近已知可用配置)
| - checkpoints
| - uid1 (用 uid1 来标识的对象版本目录)
| - resourceVersion1 (uid1 对象 resourceVersion1 版本下所有解压文件的目录)
| - ...
| - ...
了解节点配置错误信息 下表描述了使用动态 kubelet 配置时可能发生的错误消息。
你可以在 kubelet 日志中搜索相同的文本来获取有关错误的其他详细信息和上下文。
理解 node.status.config.error 消息 错误信息 可能的原因 failed to load config, see Kubelet log for details kubelet 可能无法解析下载配置的有效负载,或者当尝试从磁盘中加载有效负载时,遇到文件系统错误。 failed to validate config, see Kubelet log for details 有效负载中的配置,与命令行标志所产生的覆盖配置以及特行门控的组合、配置文件本身、远程负载被 kubelet 判定为无效。 invalid NodeConfigSource, exactly one subfield must be non-nil, but all were nil 由于 API 服务器负责对 node.spec.configSource 执行验证,检查其中是否包含至少一个非空子字段,这个消息可能意味着 kubelet 比 API 服务器版本低,因而无法识别更新的源类型。 failed to sync: failed to download config, see Kubelet log for details kubelet 无法下载配置数据。可能是 node.spec.configSource 无法解析为具体的 API 对象,或者网络错误破坏了下载。处于此错误状态时,kubelet 将重新尝试下载。 failed to sync: internal failure, see Kubelet log for details kubelet 遇到了一些内部问题,因此无法更新其配置。 例如:发生文件系统错误或无法从内部缓存中读取对象。 internal failure, see Kubelet log for details 在对配置进行同步的循环之外操作配置时,kubelet 遇到了一些内部问题。
接下来 4.2.23 - 声明网络策略 本文可以帮助你开始使用 Kubernetes 的
NetworkPolicy API
声明网络策略去管理 Pod 之间的通信
注意:
本部分链接到提供 Kubernetes 所需功能的第三方项目。Kubernetes 项目作者不负责这些项目。此页面遵循CNCF 网站指南 ,按字母顺序列出项目。要将项目添加到此列表中,请在提交更改之前阅读内容指南 。准备开始
你必须拥有一个 Kubernetes 的集群,同时你的 Kubernetes 集群必须带有 kubectl 命令行工具。
如果你还没有集群,你可以通过 Minikube 构建一
个你自己的集群,或者你可以使用下面任意一个 Kubernetes 工具构建:
您的 Kubernetes 服务器版本必须不低于版本 v1.8.
要获知版本信息,请输入
kubectl version.
你首先需要有一个支持网络策略的 Kubernetes 集群。已经有许多支持 NetworkPolicy 的网络提供商,包括:
创建一个nginx Deployment 并且通过服务将其暴露 为了查看 Kubernetes 网络策略是怎样工作的,可以从创建一个nginx Deployment 并且通过服务将其暴露开始
kubectl create deployment nginx --image= nginx
deployment.apps/nginx created
将此 Deployment 以名为 nginx 的 Service 暴露出来:
kubectl expose deployment nginx --port= 80
service/nginx exposed
上述命令创建了一个带有一个 nginx 的 Deployment,并将之通过名为 nginx 的
Service 暴露出来。名为 nginx 的 Pod 和 Deployment 都位于 default
名字空间内。
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
svc/kubernetes 10.100.0.1 <none> 443/TCP 46m
svc/nginx 10.100.0.16 <none> 80/TCP 33s
NAME READY STATUS RESTARTS AGE
po/nginx-701339712-e0qfq 1/1 Running 0 35s
通过从 Pod 访问服务对其进行测试 你应该可以从其它的 Pod 访问这个新的 nginx 服务。
要从 default 命名空间中的其它s Pod 来访问该服务。可以启动一个 busybox 容器:
kubectl run busybox --rm -ti --image= busybox /bin/sh
在你的 Shell 中,运行下面的命令:
wget --spider --timeout= 1 nginx
Connecting to nginx (10.100.0.16:80)
remote file exists
限制 nginx 服务的访问 如果想限制对 nginx 服务的访问,只让那些拥有标签 access: true 的 Pod 访问它,
那么可以创建一个如下所示的 NetworkPolicy 对象:
apiVersion : networking.k8s.io/v1
kind : NetworkPolicy
metadata :
name : access-nginx
spec :
podSelector :
matchLabels :
app : nginx
ingress :
- from :
- podSelector :
matchLabels :
access : "true"
NetworkPolicy 对象的名称必须是一个合法的
DNS 子域名 .
说明: NetworkPolicy 中包含选择策略所适用的 Pods 集合的 podSelector。
你可以看到上面的策略选择的是带有标签 app=nginx 的 Pods。
此标签是被自动添加到 nginx Deployment 中的 Pod 上的。
如果 podSelector 为空,则意味着选择的是名字空间中的所有 Pods。
为服务指定策略 使用 kubectl 根据上面的 nginx-policy.yaml 文件创建一个 NetworkPolicy:
kubectl apply -f https://k8s.io/examples/service/networking/nginx-policy.yaml
networkpolicy.networking.k8s.io/access-nginx created
测试没有定义访问标签时访问服务 如果你尝试从没有设定正确标签的 Pod 中去访问 nginx 服务,请求将会超时:
kubectl run busybox --rm -ti --image= busybox -- /bin/sh
在 Shell 中运行命令:
wget --spider --timeout= 1 nginx
Connecting to nginx (10.100.0.16:80)
wget: download timed out
定义访问标签后再次测试 创建一个拥有正确标签的 Pod,你将看到请求是被允许的:
kubectl run busybox --rm -ti --labels= "access=true" --image= busybox -- /bin/sh
在 Shell 中运行命令:
wget --spider --timeout= 1 nginx
Connecting to nginx (10.100.0.16:80)
remote file exists
4.2.24 - 安全地清空一个节点 本页展示了如何在确保 PodDisruptionBudget 的前提下,安全地清空一个节点 。
准备开始 您的 Kubernetes 服务器版本必须不低于版本 1.5.
要获知版本信息,请输入 kubectl version.
此任务假定你已经满足了以下先决条件:
为了确保你的负载在维护期间仍然可用,你可以配置一个 PodDisruptionBudget 。
如果可用性对于正在清空的该节点上运行或可能在该节点上运行的任何应用程序很重要,
首先 配置一个 PodDisruptionBudgets 并继续遵循本指南。
使用 kubectl drain 从服务中删除一个节点 在对节点执行维护(例如内核升级、硬件维护等)之前,
可以使用 kubectl drain 从节点安全地逐出所有 Pods。
安全的驱逐过程允许 Pod 的容器
体面地终止 ,
并确保满足指定的 PodDisruptionBudgets。
说明: 默认情况下,
kubectl drain 将忽略节点上不能杀死的特定系统 Pod;
有关更多细节,请参阅
kubectl drain 文档。
kubectl drain 的成功返回,表明所有的 Pods(除了上一段中描述的被排除的那些),
已经被安全地逐出(考虑到期望的终止宽限期和你定义的 PodDisruptionBudget)。
然后就可以安全地关闭节点,
比如关闭物理机器的电源,如果它运行在云平台上,则删除它的虚拟机。
首先,确定想要清空的节点的名称。可以用以下命令列出集群中的所有节点:
接下来,告诉 Kubernetes 清空节点:
kubectl drain <node name>
一旦它返回(没有报错),
你就可以下线此节点(或者等价地,如果在云平台上,删除支持该节点的虚拟机)。
如果要在维护操作期间将节点留在集群中,则需要运行:
kubectl uncordon <node name>
然后告诉 Kubernetes,它可以继续在此节点上调度新的 Pods。
并行清空多个节点 kubectl drain 命令一次只能发送给一个节点。
但是,你可以在不同的终端或后台为不同的节点并行地运行多个 kubectl drain 命令。
同时运行的多个 drain 命令仍然遵循你指定的 PodDisruptionBudget 。
例如,如果你有一个三副本的 StatefulSet,
并设置了一个 PodDisruptionBudget,指定 minAvailable: 2。
如果所有的三个 Pod 均就绪,并且你并行地发出多个 drain 命令,
那么 kubectl drain 只会从 StatefulSet 中逐出一个 Pod,
因为 Kubernetes 会遵守 PodDisruptionBudget 并确保在任何时候只有一个 Pod 不可用
(最多不可用 Pod 个数的计算方法:replicas - minAvailable)。
任何会导致就绪副本数量低于指定预算的清空操作都将被阻止。
驱逐 API 如果你不喜欢使用
kubectl drain
(比如避免调用外部命令,或者更细化地控制 pod 驱逐过程),
你也可以用驱逐 API 通过编程的方式达到驱逐的效果。
首先应该熟悉使用
Kubernetes 语言客户端 。
Pod 的 Eviction 子资源可以看作是一种策略控制的 DELETE 操作,作用于 Pod 本身。
要尝试驱逐(更准确地说,尝试 创建 一个 Eviction),需要用 POST 发出所尝试的操作。这里有一个例子:
{
"apiVersion" : "policy/v1beta1" ,
"kind" : "Eviction" ,
"metadata" : {
"name" : "quux" ,
"namespace" : "default"
}
}
你可以使用 curl 尝试驱逐:
curl -v -H 'Content-type: application/json' http://127.0.0.1:8080/api/v1/namespaces/default/pods/quux/eviction -d @eviction.json
API 可以通过以下三种方式之一进行响应:
如果驱逐被授权,那么 Pod 将被删掉,并且你会收到 200 OK,
就像你向 Pod 的 URL 发送了 DELETE 请求一样。 如果按照预算中规定,目前的情况不允许的驱逐,你会收到 429 Too Many Requests。
这通常用于对 一些 请求进行通用速率限制,
但这里我们的意思是:此请求 现在 不允许,但以后可能会允许。
目前,调用者不会得到任何 Retry-After 的提示,但在将来的版本中可能会得到。 如果有一些错误的配置,比如多个预算指向同一个 Pod,你将得到 500 Internal Server Error。 对于一个给定的驱逐请求,有两种情况:
没有匹配这个 Pod 的预算。这种情况,服务器总是返回 200 OK。 至少匹配一个预算。在这种情况下,上述三种回答中的任何一种都可能适用。 驱逐阻塞 在某些情况下,应用程序可能会到达一个中断状态,除了 429 或 500 之外,它将永远不会返回任何内容。
例如 ReplicaSet 创建的替换 Pod 没有变成就绪状态,或者被驱逐的最后一个
Pod 有很长的终止宽限期,就会发生这种情况。
在这种情况下,有两种可能的解决方案:
中止或暂停自动操作。调查应用程序卡住的原因,并重新启动自动化。 经过适当的长时间等待后,从集群中删除 Pod 而不是使用驱逐 API。 Kubernetes 并没有具体说明在这种情况下应该采取什么行为,
这应该由应用程序所有者和集群所有者紧密沟通,并达成对行动一致意见。
接下来 4.2.25 - 开发云控制器管理器 FEATURE STATE: Kubernetes v1.11 [beta]
组件 cloud-controller-manager 是 云控制器管理器是指嵌入特定云的控制逻辑的
控制平面 组件。
云控制器管理器允许您链接聚合到云提供商的应用编程接口中,
并分离出相互作用的组件与您的集群交互的组件。
通过分离 Kubernetes 和底层云基础设置之间的互操作性逻辑,
云控制器管理器组件使云提供商能够以不同于 Kubernetes 主项目的速度进行发布新特征。
背景 由于云驱动的开发和发布与 Kubernetes 项目本身步调不同,将特定于云环境
的代码抽象到 cloud-controller-manager 二进制组件有助于云厂商独立于
Kubernetes 核心代码推进其驱动开发。
Kubernetes 项目提供 cloud-controller-manager 的框架代码,其中包含 Go
语言的接口,便于你(或者你的云驱动提供者)接驳你自己的实现。
这意味着每个云驱动可以通过从 Kubernetes 核心代码导入软件包来实现一个
cloud-controller-manager;每个云驱动会通过调用
cloudprovider.RegisterCloudProvider 接口来注册其自身实现代码,从而更新
记录可用云驱动的全局变量。
开发 Out of Tree 要为你的云环境构建一个 out-of-tree 云控制器管理器:
使用满足 cloudprovider.Interface
的实现创建一个 Go 语言包。 使用来自 Kubernetes 核心代码库的
cloud-controller-manager 中的 main.go
作为 main.go 的模板。如上所述,唯一的区别应该是将导入的云包。 在 main.go 中导入你的云包,确保你的包有一个 init 块来运行
cloudprovider.RegisterCloudProvider 。 很多云驱动都将其控制器管理器代码以开源代码的形式公开。
如果你在开发一个新的 cloud-controller-manager,你可以选择某个 out-of-tree
云控制器管理器作为出发点。
In Tree 对于 in-tree 驱动,你可以将 in-tree 云控制器管理器作为群集中的
Daemonset 来运行。
有关详细信息,请参阅云控制器管理器管理 。
4.2.26 - 开启服务拓扑 本页面提供了在 Kubernetes 中启用服务拓扑的概述。
准备开始
你必须拥有一个 Kubernetes 的集群,同时你的 Kubernetes 集群必须带有 kubectl 命令行工具。
如果你还没有集群,你可以通过 Minikube 构建一
个你自己的集群,或者你可以使用下面任意一个 Kubernetes 工具构建:
要获知版本信息,请输入
kubectl version.
介绍 服务拓扑(Service Topology) 使服务能够根据集群中的 Node 拓扑来路由流量。
比如,服务可以指定将流量优先路由到与客户端位于同一节点或者同一可用区域的端点上。
先决条件 需要下面列的先决条件,才能启用拓扑感知的服务路由:
启用服务拓扑 FEATURE STATE: Kubernetes v1.17 [alpha]
要启用服务拓扑功能,需要为所有 Kubernetes 组件启用 ServiceTopology 和 EndpointSlice 特性门控:
--feature-gates="ServiceTopology=true,EndpointSlice=true"
接下来 4.2.27 - 控制节点上的 CPU 管理策略 FEATURE STATE: Kubernetes v1.12 [beta]
按照设计,Kubernetes 对 pod 执行相关的很多方面进行了抽象,使得用户不必关心。
然而,为了正常运行,有些工作负载要求在延迟和/或性能方面有更强的保证。
为此,kubelet 提供方法来实现更复杂的负载放置策略,同时保持抽象,避免显式的放置指令。
准备开始
你必须拥有一个 Kubernetes 的集群,同时你的 Kubernetes 集群必须带有 kubectl 命令行工具。
如果你还没有集群,你可以通过 Minikube 构建一
个你自己的集群,或者你可以使用下面任意一个 Kubernetes 工具构建:
要获知版本信息,请输入
kubectl version.
CPU 管理策略 默认情况下,kubelet 使用 CFS 配额
来执行 Pod 的 CPU 约束。
当节点上运行了很多 CPU 密集的 Pod 时,工作负载可能会迁移到不同的 CPU 核,
这取决于调度时 Pod 是否被扼制,以及哪些 CPU 核是可用的。
许多工作负载对这种迁移不敏感,因此无需任何干预即可正常工作。
然而,有些工作负载的性能明显地受到 CPU 缓存亲和性以及调度延迟的影响。
对此,kubelet 提供了可选的 CPU 管理策略,来确定节点上的一些分配偏好。
配置 CPU 管理策略通过 kubelet 参数 --cpu-manager-policy 来指定。支持两种策略:
none: 默认策略,表示现有的调度行为。static: 允许为节点上具有某些资源特征的 pod 赋予增强的 CPU 亲和性和独占性。CPU 管理器定期通过 CRI 写入资源更新,以保证内存中 CPU 分配与 cgroupfs 一致。
同步频率通过新增的 Kubelet 配置参数 --cpu-manager-reconcile-period 来设置。
如果不指定,默认与 --node-status-update-frequency 的周期相同。
none 策略 none 策略显式地启用现有的默认 CPU 亲和方案,不提供操作系统调度器默认行为之外的亲和性策略。
通过 CFS 配额来实现 Guaranteed pods
的 CPU 使用限制。
static 策略 static 策略针对具有整数型 CPU requests 的 Guaranteed Pod ,它允许该类 Pod
中的容器访问节点上的独占 CPU 资源。这种独占性是使用
cpuset cgroup 控制器 来实现的。
说明: 诸如容器运行时和 kubelet 本身的系统服务可以继续在这些独占 CPU 上运行。独占性仅针对其他 Pod。
说明: CPU 管理器不支持运行时下线和上线 CPUs。此外,如果节点上的在线 CPUs 集合发生变化,
则必须驱逐节点上的 Pod,并通过删除 kubelet 根目录中的状态文件 cpu_manager_state
来手动重置 CPU 管理器。
该策略管理一个共享 CPU 资源池,最初,该资源池包含节点上所有的 CPU 资源。可用
的独占性 CPU 资源数量等于节点的 CPU 总量减去通过 --kube-reserved 或 --system-reserved 参数保留的 CPU 。从1.17版本开始,CPU保留列表可以通过 kublet 的 '--reserved-cpus' 参数显式地设置。
通过 '--reserved-cpus' 指定的显式CPU列表优先于使用 '--kube-reserved' 和 '--system-reserved' 参数指定的保留CPU。 通过这些参数预留的 CPU 是以整数方式,按物理内
核 ID 升序从初始共享池获取的。 共享池是 BestEffort 和 Burstable pod 运行
的 CPU 集合。Guaranteed pod 中的容器,如果声明了非整数值的 CPU requests ,也将运行在共享池的 CPU 上。只有 Guaranteed pod 中,指定了整数型 CPU requests 的容器,才会被分配独占 CPU 资源。
说明: 当启用 static 策略时,要求使用 --kube-reserved 和/或 --system-reserved 或
--reserved-cpus 来保证预留的 CPU 值大于零。
这是因为零预留 CPU 值可能使得共享池变空。
当 Guaranteed Pod 调度到节点上时,如果其容器符合静态分配要求,
相应的 CPU 会被从共享池中移除,并放置到容器的 cpuset 中。
因为这些容器所使用的 CPU 受到调度域本身的限制,所以不需要使用 CFS 配额来进行 CPU 的绑定。
换言之,容器 cpuset 中的 CPU 数量与 Pod 规约中指定的整数型 CPU limit 相等。
这种静态分配增强了 CPU 亲和性,减少了 CPU 密集的工作负载在节流时引起的上下文切换。
考虑以下 Pod 规格的容器:
spec :
containers :
- name : nginx
image : nginx
该 Pod 属于 BestEffort QoS 类型,因为其未指定 requests 或 limits 值。
所以该容器运行在共享 CPU 池中。
spec :
containers :
- name : nginx
image : nginx
resources :
limits :
memory : "200Mi"
requests :
memory : "100Mi"
该 Pod 属于 Burstable QoS 类型,因为其资源 requests 不等于 limits,且未指定 cpu 数量。
所以该容器运行在共享 CPU 池中。
spec :
containers :
- name : nginx
image : nginx
resources :
limits :
memory : "200Mi"
cpu : "2"
requests :
memory : "100Mi"
cpu : "1"
该 pod 属于 Burstable QoS 类型,因为其资源 requests 不等于 limits。
所以该容器运行在共享 CPU 池中。
spec :
containers :
- name : nginx
image : nginx
resources :
limits :
memory : "200Mi"
cpu : "2"
requests :
memory : "200Mi"
cpu : "2"
该 Pod 属于 Guaranteed QoS 类型,因为其 requests 值与 limits相等。
同时,容器对 CPU 资源的限制值是一个大于或等于 1 的整数值。
所以,该 nginx 容器被赋予 2 个独占 CPU。
spec :
containers :
- name : nginx
image : nginx
resources :
limits :
memory : "200Mi"
cpu : "1.5"
requests :
memory : "200Mi"
cpu : "1.5"
该 Pod 属于 Guaranteed QoS 类型,因为其 requests 值与 limits相等。
但是容器对 CPU 资源的限制值是一个小数。所以该容器运行在共享 CPU 池中。
spec :
containers :
- name : nginx
image : nginx
resources :
limits :
memory : "200Mi"
cpu : "2"
该 Pod 属于 Guaranteed QoS 类型,因其指定了 limits 值,同时当未显式指定时,
requests 值被设置为与 limits 值相等。
同时,容器对 CPU 资源的限制值是一个大于或等于 1 的整数值。
所以,该 nginx 容器被赋予 2 个独占 CPU。
4.2.28 - 控制节点上的拓扑管理策略 FEATURE STATE: Kubernetes v1.18 [beta]
越来越多的系统利用 CPU 和硬件加速器的组合来支持对延迟要求较高的任务和高吞吐量的并行计算。
这类负载包括电信、科学计算、机器学习、金融服务和数据分析等。
此类混合系统即用于构造这些高性能环境。
为了获得最佳性能,需要进行与 CPU 隔离、内存和设备局部性有关的优化。
但是,在 Kubernetes 中,这些优化由各自独立的组件集合来处理。
拓扑管理器(Topology Manager) 是一个 kubelet 的一部分,旨在协调负责这些优化的一组组件。
准备开始
你必须拥有一个 Kubernetes 的集群,同时你的 Kubernetes 集群必须带有 kubectl 命令行工具。
如果你还没有集群,你可以通过 Minikube 构建一
个你自己的集群,或者你可以使用下面任意一个 Kubernetes 工具构建:
您的 Kubernetes 服务器版本必须不低于版本 v1.18.
要获知版本信息,请输入
kubectl version.
拓扑管理器如何工作 在引入拓扑管理器之前, Kubernetes 中的 CPU 和设备管理器相互独立地做出资源分配决策。
这可能会导致在多处理系统上出现并非期望的资源分配;由于这些与期望相左的分配,对性能或延迟敏感的应用将受到影响。
这里的不符合期望意指,例如, CPU 和设备是从不同的 NUMA 节点分配的,因此会导致额外的延迟。
拓扑管理器是一个 Kubelet 组件,扮演信息源的角色,以便其他 Kubelet 组件可以做出与拓扑结构相对应的资源分配决定。
拓扑管理器为组件提供了一个称为 建议供应者(Hint Providers) 的接口,以发送和接收拓扑信息。
拓扑管理器具有一组节点级策略,具体说明如下。
拓扑管理器从 建议提供者 接收拓扑信息,作为表示可用的 NUMA 节点和首选分配指示的位掩码。
拓扑管理器策略对所提供的建议执行一组操作,并根据策略对提示进行约减以得到最优解;如果存储了与预期不符的建议,则该建议的优选字段将被设置为 false。
在当前策略中,首选的是最窄的优选掩码。
所选建议将被存储为拓扑管理器的一部分。
取决于所配置的策略,所选建议可用来决定节点接受或拒绝 Pod 。
之后,建议会被存储在拓扑管理器中,供 建议提供者 进行资源分配决策时使用。
启用拓扑管理器功能特性 对拓扑管理器的支持要求启用 TopologyManager
特性门控 。
从 Kubernetes 1.18 版本开始,这一特性默认是启用的。
拓扑管理器作用域和策略 拓扑管理器目前:
对所有 QoS 类的 Pod 执行对齐操作 针对建议提供者所提供的拓扑建议,对请求的资源进行对齐 如果满足这些条件,则拓扑管理器将对齐请求的资源。
为了定制如何进行对齐,拓扑管理器提供了两种不同的方式:scope 和 policy。
scope 定义了资源对齐时你所希望使用的粒度(例如,是在 pod 还是 container 级别)。
policy 定义了对齐时实际使用的策略(例如,best-effort、restricted、single-numa-node 等等)。
可以在下文找到现今可用的各种 scopes 和 policies 的具体信息。
说明: 为了将 Pod 规约中的 CPU 资源与其他请求资源对齐,CPU 管理器需要被启用并且
节点上应配置了适当的 CPU 管理器策略。
参看
控制 CPU 管理策略 .
拓扑管理器作用域 拓扑管理器可以在以下不同的作用域内进行资源对齐:
在 kubelet 启动时,可以使用 --topology-manager-scope 标志来选择其中任一选项。
容器作用域 默认使用的是 container 作用域。
在该作用域内,拓扑管理器依次进行一系列的资源对齐,
也就是,对每一个容器(包含在一个 Pod 里)计算单独的对齐。
换句话说,在该特定的作用域内,没有根据特定的 NUMA 节点集来把容器分组的概念。
实际上,拓扑管理器会把单个容器任意地对齐到 NUMA 节点上。
容器分组的概念是在以下的作用域内特别实现的,也就是 pod 作用域。
Pod 作用域 使用命令行选项 --topology-manager-scope=pod 来启动 kubelet,就可以选择 pod 作用域。
该作用域允许把一个 Pod 里的所有容器作为一个分组,分配到一个共同的 NUMA 节点集。
也就是,拓扑管理器会把一个 Pod 当成一个整体,
并且试图把整个 Pod(所有容器)分配到一个单个的 NUMA 节点或者一个共同的 NUMA 节点集。
以下的例子说明了拓扑管理器在不同的场景下使用的对齐方式:
所有容器可以被分配到一个单一的 NUMA 节点; 所有容器可以被分配到一个共享的 NUMA 节点集。 整个 Pod 所请求的某种资源总量是根据
有效 request/limit
公式来计算的,
因此,对某一种资源而言,该总量等于以下数值中的最大值:
pod 作用域与 single-numa-node 拓扑管理器策略一起使用,
对于延时敏感的工作负载,或者对于进行 IPC 的高吞吐量应用程序,都是特别有价值的。
把这两个选项组合起来,你可以把一个 Pod 里的所有容器都放到一个单个的 NUMA 节点,
使得该 Pod 消除了 NUMA 之间的通信开销。
在 single-numa-node 策略下,只有当可能的分配方案中存在合适的 NUMA 节点集时,Pod 才会被接受。
重新考虑上述的例子:
节点集只包含单个 NUMA 节点时,Pod 就会被接受, 然而,节点集包含多个 NUMA 节点时,Pod 就会被拒绝
(因为满足该分配方案需要两个或以上的 NUMA 节点,而不是单个 NUMA 节点)。 简要地说,拓扑管理器首先计算出 NUMA 节点集,然后使用拓扑管理器策略来测试该集合,
从而决定拒绝或者接受 Pod。
拓扑管理器策略 拓扑管理器支持四种分配策略。
你可以通过 Kubelet 标志 --topology-manager-policy 设置策略。
所支持的策略有四种:
none (默认)best-effortrestrictedsingle-numa-node说明: 如果拓扑管理器配置使用 Pod 作用域,
那么在策略考量一个容器时,该容器反映的是整个 Pod 的要求,
于是该 Pod 里的每个容器都会得到 相同的 拓扑对齐决定。
none 策略 这是默认策略,不执行任何拓扑对齐。
best-effort 策略 对于 Guaranteed 类的 Pod 中的每个容器,具有 best-effort 拓扑管理策略的
kubelet 将调用每个建议提供者以确定资源可用性。
使用此信息,拓扑管理器存储该容器的首选 NUMA 节点亲和性。
如果亲和性不是首选,则拓扑管理器将存储该亲和性,并且无论如何都将 pod 接纳到该节点。
之后 建议提供者 可以在进行资源分配决策时使用这个信息。
restricted 策略 对于 Guaranteed 类 Pod 中的每个容器, 配置了 restricted 拓扑管理策略的 kubelet
调用每个建议提供者以确定其资源可用性。。
使用此信息,拓扑管理器存储该容器的首选 NUMA 节点亲和性。
如果亲和性不是首选,则拓扑管理器将从节点中拒绝此 Pod 。
这将导致 Pod 处于 Terminated 状态,且 Pod 无法被节点接纳。
一旦 Pod 处于 Terminated 状态,Kubernetes 调度器将不会尝试重新调度该 Pod。
建议使用 ReplicaSet 或者 Deployment 来重新部署 Pod。
还可以通过实现外部控制环,以启动对具有 Topology Affinity 错误的 Pod 的重新部署。
如果 Pod 被允许运行在某节点,则 建议提供者 可以在做出资源分配决定时使用此信息。
single-numa-node 策略 对于 Guaranteed 类 Pod 中的每个容器, 配置了 single-numa-nodde 拓扑管理策略的
kubelet 调用每个建议提供者以确定其资源可用性。
使用此信息,拓扑管理器确定单 NUMA 节点亲和性是否可能。
如果是这样,则拓扑管理器将存储此信息,然后 建议提供者 可以在做出资源分配决定时使用此信息。
如果不可能,则拓扑管理器将拒绝 Pod 运行于该节点。
这将导致 Pod 处于 Terminated 状态,且 Pod 无法被节点接受。
一旦 Pod 处于 Terminated 状态,Kubernetes 调度器将不会尝试重新调度该 Pod。
建议使用 ReplicaSet 或者 Deployment 来重新部署 Pod。
还可以通过实现外部控制环,以触发具有 Topology Affinity 错误的 Pod 的重新部署。
Pod 与拓扑管理器策略的交互 考虑以下 pod 规范中的容器:
spec :
containers :
- name : nginx
image : nginx
该 Pod 以 BestEffort QoS 类运行,因为没有指定资源 requests 或 limits。
spec :
containers :
- name : nginx
image : nginx
resources :
limits :
memory : "200Mi"
requests :
memory : "100Mi"
由于 requests 数少于 limits,因此该 Pod 以 Burstable QoS 类运行。
如果选择的策略是 none 以外的任何其他策略,拓扑管理器都会评估这些 Pod 的规范。
拓扑管理器会咨询建议提供者,获得拓扑建议。
若策略为 static,则 CPU 管理器策略会返回默认的拓扑建议,因为这些 Pod
并没有显式地请求 CPU 资源。
spec :
containers :
- name : nginx
image : nginx
resources :
limits :
memory : "200Mi"
cpu : "2"
example.com/device : "1"
requests :
memory : "200Mi"
cpu : "2"
example.com/device : "1"
此 Pod 以 Guaranteed QoS 类运行,因为其 requests 值等于 limits 值。
spec :
containers :
- name : nginx
image : nginx
resources :
limits :
example.com/deviceA : "1"
example.com/deviceB : "1"
requests :
example.com/deviceA : "1"
example.com/deviceB : "1"
因为未指定 CPU 和内存请求,所以 Pod 以 BestEffort QoS 类运行。
拓扑管理器将考虑以上两个 Pod。拓扑管理器将咨询建议提供者即 CPU 和设备管理器,以获取 Pod 的拓扑提示。
对于 Guaranteed 类的 CPU 请求数为整数的 Pod,static CPU 管理器策略将返回与 CPU 请求有关的提示,
而设备管理器将返回有关所请求设备的提示。
对于 Guaranteed 类的 CPU 请求可共享的 Pod,static CPU
管理器策略将返回默认的拓扑提示,因为没有排他性的 CPU 请求;而设备管理器
则针对所请求的设备返回有关提示。
在上述两种 Guaranteed Pod 的情况中,none CPU 管理器策略会返回默认的拓扑提示。
对于 BestEffort Pod,由于没有 CPU 请求,static CPU 管理器策略将发送默认提示,
而设备管理器将为每个请求的设备发送提示。
基于此信息,拓扑管理器将为 Pod 计算最佳提示并存储该信息,并且供
提示提供程序在进行资源分配时使用。
已知的局限性 拓扑管理器所能处理的最大 NUMA 节点个数是 8。若 NUMA 节点数超过 8,
枚举可能的 NUMA 亲和性并为之生成提示时会发生状态爆炸。 调度器不支持拓扑功能,因此可能会由于拓扑管理器的原因而在节点上进行调度,然后在该节点上调度失败。 设备管理器和 CPU 管理器时能够采纳拓扑管理器 HintProvider 接口的唯一两个组件。
这意味着 NUMA 对齐只能针对 CPU 管理器和设备管理器所管理的资源实现。
内存和大页面在拓扑管理器决定 NUMA 对齐时都还不会被考虑在内。 4.2.29 - 搭建高可用的 Kubernetes Masters FEATURE STATE: Kubernetes 1.5 [alpha]
你可以在谷歌计算引擎(GCE)的 kubeup 或 kube-down 脚本中复制 Kubernetes Master。
本文描述了如何使用 kube-up/down 脚本来管理高可用(HA)的 Master,
以及如何使用 GCE 实现高可用控制节点。
准备开始
你必须拥有一个 Kubernetes 的集群,同时你的 Kubernetes 集群必须带有 kubectl 命令行工具。
如果你还没有集群,你可以通过 Minikube 构建一
个你自己的集群,或者你可以使用下面任意一个 Kubernetes 工具构建:
要获知版本信息,请输入
kubectl version.
启动一个兼容高可用的集群 要创建一个新的兼容高可用的集群,你必须在 kubeup 脚本中设置以下标志:
MULTIZONE=true - 为了防止从不同于服务器的默认区域的区域中删除 kubelets 副本。
如果你希望在不同的区域运行副本,那么这一项是必需并且推荐的。
ENABLE_ETCD_QUORUM_READ=true - 确保从所有 API 服务器读取数据时将返回最新的数据。
如果为 true,读操作将被定向到主 etcd 副本。可以选择将这个值设置为 true,
那么读取将更可靠,但也会更慢。
你还可以指定一个 GCE 区域,在这里创建第一个主节点副本。设置以下标志:
KUBE_GCE_ZONE=zone - 将运行第一个主节点副本的区域。下面的命令演示在 GCE europe-west1-b 区域中设置一个兼容高可用的集群:
MULTIZONE = true KUBE_GCE_ZONE = europe-west1-b ENABLE_ETCD_QUORUM_READS = true ./cluster/kube-up.sh
注意,上面的命令创建一个只有单一主节点的集群;
但是,你可以使用后续命令将新的主节点副本添加到集群中。
增加一个新的主节点副本 在创建了兼容高可用的集群之后,可以向其中添加主节点副本。
你可以使用带有如下标记的 kubeup 脚本添加主节点副本:
你无需设置 MULTIZONE 或 ENABLE_ETCD_QUORUM_READS 标志,因为他们可以从兼容高可用的集群中继承。
使用下面的命令可以复制现有兼容高可用的集群上的 Master:
KUBE_GCE_ZONE = europe-west1-c KUBE_REPLICATE_EXISTING_MASTER = true ./cluster/kube-up.sh
删除主节点副本 你可以使用一个 kube-down 脚本从高可用集群中删除一个主节点副本,并可以使用以下标记:
KUBE_DELETE_NODES=false - 限制删除 kubelets。
KUBE_GCE_ZONE=zone - 将移除主节点副本的区域。
KUBE_REPLICA_NAME=replica_name - (可选)要删除的主节点副本的名称。
如果为空:将删除给定区域中的所有副本。
使用下面的命令可以从一个现有的高可用集群中删除一个 Master副本:
KUBE_DELETE_NODES = false KUBE_GCE_ZONE = europe-west1-c ./cluster/kube-down.sh
处理主节点副本失败 如果高可用集群中的一个主节点副本失败,最佳实践是从集群中删除副本,
并在相同的区域中添加一个新副本。
下面的命令演示了这个过程:
删除失败的副本: KUBE_DELETE_NODES = false KUBE_GCE_ZONE = replica_zone KUBE_REPLICA_NAME = replica_name ./cluster/kube-down.sh
在原有位置增加一个新副本: KUBE_GCE_ZONE = replica-zone KUBE_REPLICATE_EXISTING_MASTER = true ./cluster/kube-up.sh
高可用集群复制主节点的最佳实践 尝试将主节点副本放置在不同的区域。在某区域故障时,放置在该区域内的所有主机都将失败。
为了在区域故障中幸免,请同样将工作节点放置在多区域中
(详情请见多区域 )。
不要使用具有两个主节点副本的集群。在双副本集群上达成一致需要在更改持久状态时
两个副本都处于运行状态。
因此,两个副本都是需要的,任一副本的失败都会将集群带入多数失败状态。
因此,就高可用而言,双副本集群不如单个副本集群。
添加主节点副本时,集群状态(etcd)会被复制到一个新实例。如果集群很大,
可能需要很长时间才能复制它的状态。
这个操作可以通过迁移 etcd 数据存储来加速, 详情参见
这里
(我们正在考虑在未来添加对迁移 etcd 数据存储的支持)。
实现说明
概述 每个主节点副本将以以下模式运行以下组件:
etcd 实例: 所有实例将会以共识方式组建集群;
API 服务器: 每个服务器将与本地 etcd 通信——集群中的所有 API 服务器都可用;
控制器、调度器和集群自动扩缩器:将使用租约机制 —— 每个集群中只有一个实例是可用的;
插件管理器:每个管理器将独立工作,试图保持插件同步。
此外,在 API 服务器前面将有一个负载均衡器,用于将外部和内部通信路由到他们。
负载均衡 启动第二个主节点副本时,将创建一个包含两个副本的负载均衡器,
并将第一个副本的 IP 地址提升为负载均衡器的 IP 地址。
类似地,在删除倒数第二个主节点副本之后,将删除负载均衡器,
并将其 IP 地址分配给最后一个剩余的副本。
请注意,创建和删除负载均衡器是复杂的操作,可能需要一些时间(约20分钟)来同步。
主节点服务 & kubelets Kubernetes 并不试图在其服务中保持 apiserver 的列表为最新,
相反,它将将所有访问请求指向外部 IP:
在拥有一个主节点的集群中,IP 指向单一的主节点, 在拥有多个主节点的集群中,IP 指向主节点前面的负载均衡器。 类似地,kubelets 将使用外部 IP 与主节点通信。
主节点证书 Kubernetes 为每个副本的外部公共 IP 和本地 IP 生成主节点 TLS 证书。
副本的临时公共 IP 没有证书;
要通过其临时公共 IP 访问副本,必须跳过 TLS 检查。
etcd 集群 为了允许 etcd 组建集群,需开放 etcd 实例之间通信所需的端口(用于集群内部通信)。
为了使这种部署安全,etcd 实例之间的通信使用 SSL 进行鉴权。
API 服务器标识 FEATURE STATE: Kubernetes v1.20 [alpha]
使用 API 服务器标识功能需要启用特性门控 ,
该功能默认不启用。
你可以在启动 API 服务器 的时候启用特性门控 APIServerIdentity 来激活 API 服务器标识:
kube-apiserver \
--feature-gates= APIServerIdentity = true \
# …其他标记照常
在启动引导过程中,每个 kube-apiserver 会给自己分配一个唯一 ID。
该 ID 的格式是 kube-apiserver-{UUID}。
每个 kube-apiserver 会在 kube-system 名字空间 里创建一个 Lease 对象 。
Lease 对象的名字是 kube-apiserver 的唯一 ID。
Lease 对象包含一个标签 k8s.io/component=kube-apiserver。
每个 kube-apiserver 每过 IdentityLeaseRenewIntervalSeconds(默认是 10 秒)就会刷新它的 Lease 对象。
每个 kube-apiserver 每过 IdentityLeaseDurationSeconds(默认是 3600 秒)也会检查所有 kube-apiserver 的标识 Lease 对象,
并且会删除超过 IdentityLeaseDurationSeconds 时间还没被刷新的 Lease 对象。
可以在 kube-apiserver 的 identity-lease-renew-interval-seconds
和 identity-lease-duration-seconds 标记里配置 IdentityLeaseRenewIntervalSeconds 和 IdentityLeaseDurationSeconds。
启用该功能是使用 HA API 服务器协调相关功能(例如,StorageVersionAPI 特性门控)的前提条件。
拓展阅读 自动化高可用集群部署 - 设计文档
4.2.30 - 改变默认 StorageClass 本文展示了如何改变默认的 Storage Class,它用于为没有特殊需求的 PersistentVolumeClaims 配置 volumes。
准备开始
你必须拥有一个 Kubernetes 的集群,同时你的 Kubernetes 集群必须带有 kubectl 命令行工具。
如果你还没有集群,你可以通过 Minikube 构建一
个你自己的集群,或者你可以使用下面任意一个 Kubernetes 工具构建:
要获知版本信息,请输入
kubectl version.
为什么要改变默认存储类? 取决于安装模式,你的 Kubernetes 集群可能和一个被标记为默认的已有 StorageClass 一起部署。
这个默认的 StorageClass 以后将被用于动态的为没有特定存储类需求的 PersistentVolumeClaims
配置存储。更多细节请查看
PersistentVolumeClaim 文档 。
预先安装的默认 StorageClass 可能不能很好的适应你期望的工作负载;例如,它配置的存储可能太过昂贵。
如果是这样的话,你可以改变默认 StorageClass,或者完全禁用它以防止动态配置存储。
删除默认 StorageClass 可能行不通,因为它可能会被你集群中的扩展管理器自动重建。
请查阅你的安装文档中关于扩展管理器的细节,以及如何禁用单个扩展。
改变默认 StorageClass 列出你的集群中的 StorageClasses:
输出类似这样:
NAME PROVISIONER AGE
standard ( default) kubernetes.io/gce-pd 1d
gold kubernetes.io/gce-pd 1d
默认 StorageClass 以 (default) 标记。
标记默认 StorageClass 非默认:
默认 StorageClass 的注解 storageclass.kubernetes.io/is-default-class 设置为 true。
注解的其它任意值或者缺省值将被解释为 false。
要标记一个 StorageClass 为非默认的,你需要改变它的值为 false:
kubectl patch storageclass standard -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"false"}}}'
这里的 standard 是你选择的 StorageClass 的名字。
标记一个 StorageClass 为默认的:
和前面的步骤类似,你需要添加/设置注解 storageclass.kubernetes.io/is-default-class=true。
kubectl patch storageclass <your-class-name> -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}'
请注意,最多只能有一个 StorageClass 能够被标记为默认。
如果它们中有两个或多个被标记为默认,Kubernetes 将忽略这个注解,
也就是它将表现为没有默认 StorageClass。
验证你选用的 StorageClass 为默认的:
输出类似这样:
NAME PROVISIONER AGE
standard kubernetes.io/gce-pd 1d
gold (default) kubernetes.io/gce-pd 1d
接下来 4.2.31 - 更改 PersistentVolume 的回收策略 本文展示了如何更改 Kubernetes PersistentVolume 的回收策略。
准备开始
你必须拥有一个 Kubernetes 的集群,同时你的 Kubernetes 集群必须带有 kubectl 命令行工具。
如果你还没有集群,你可以通过 Minikube 构建一
个你自己的集群,或者你可以使用下面任意一个 Kubernetes 工具构建:
要获知版本信息,请输入
kubectl version.
为什么要更改 PersistentVolume 的回收策略 PersistentVolumes 可以有多种回收策略,包括 "Retain"、"Recycle" 和 "Delete"。
对于动态配置的 PersistentVolumes 来说,默认回收策略为 "Delete"。
这表示当用户删除对应的 PersistentVolumeClaim 时,动态配置的 volume 将被自动删除。
如果 volume 包含重要数据时,这种自动行为可能是不合适的。
那种情况下,更适合使用 "Retain" 策略。
使用 "Retain" 时,如果用户删除 PersistentVolumeClaim,对应的 PersistentVolume 不会被删除。
相反,它将变为 Released 状态,表示所有的数据可以被手动恢复。
更改 PersistentVolume 的回收策略 列出你集群中的 PersistentVolumes
输出类似于这样:
NAME CAPACITY ACCESSMODES RECLAIMPOLICY STATUS CLAIM REASON AGE
pvc-b6efd8da-b7b5-11e6-9d58-0ed433a7dd94 4Gi RWO Delete Bound default/claim1 10s
pvc-b95650f8-b7b5-11e6-9d58-0ed433a7dd94 4Gi RWO Delete Bound default/claim2 6s
pvc-bb3ca71d-b7b5-11e6-9d58-0ed433a7dd94 4Gi RWO Delete Bound default/claim3 3s
这个列表同样包含了绑定到每个卷的 claims 名称,以便更容易的识别动态配置的卷。
选择你的 PersistentVolumes 中的一个并更改它的回收策略:
kubectl patch pv <your-pv-name> -p '{"spec":{"persistentVolumeReclaimPolicy":"Retain"}}'
这里的 <your-pv-name> 是你选择的 PersistentVolume 的名字。
说明: 在 Windows 系统上,你必须对包含空格的 JSONPath 模板加双引号(而不是像上面
一样为 Bash 环境使用的单引号)。这也意味着你必须使用单引号或者转义的双引号
来处理模板中的字面值。例如:
kubectl patch pv <your-pv-name> -p "{\" spec\":{\" persistentVolumeReclaimPolicy\":\" Retain\"}}"
验证你选择的 PersistentVolume 拥有正确的策略:
输出类似于这样:
NAME CAPACITY ACCESSMODES RECLAIMPOLICY STATUS CLAIM REASON AGE
pvc-b6efd8da-b7b5-11e6-9d58-0ed433a7dd94 4Gi RWO Delete Bound default/claim1 40s
pvc-b95650f8-b7b5-11e6-9d58-0ed433a7dd94 4Gi RWO Delete Bound default/claim2 36s
pvc-bb3ca71d-b7b5-11e6-9d58-0ed433a7dd94 4Gi RWO Retain Bound default/claim3 33s
在前面的输出中,你可以看到绑定到申领 default/claim3 的卷的回收策略为 Retain。
当用户删除申领 default/claim3 时,它不会被自动删除。
接下来 参考 4.2.32 - 自动扩缩集群 DNS 服务 本页展示了如何在集群中启用和配置 DNS 服务的自动扩缩功能。
准备开始 确定是否 DNS 水平 水平自动扩缩特性已经启用 在 kube-system 命名空间中列出集群中的 Deployments :
kubectl get deployment --namespace= kube-system
输出类似如下这样:
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
...
dns-autoscaler 1 1 1 1 ...
...
如果在输出中看到 “dns-autoscaler”,说明 DNS 水平自动扩缩已经启用,可以跳到
调优自动扩缩参数 。
获取 DNS Deployment 的名称 列出集群内 kube-system 名字空间中的 DNS Deployment:
kubectl get deployment -l k8s-app= kube-dns --namespace= kube-system
输出类似如下这样:
NAME READY UP-TO-DATE AVAILABLE AGE
...
coredns 2/2 2 2 ...
...
如果看不到 DNS 服务的 Deployment,你也可以通过名字来查找:
kubectl get deployment --namespace= kube-system
并在输出中寻找名称为 coredns 或 kube-dns 的 Deployment。
你的扩缩目标为:
Deployment/<your-deployment-name>
其中 <your-deployment-name> 是 DNS Deployment 的名称。
例如,如果你的 DNS Deployment 名称是 coredns,则你的扩展目标是 Deployment/coredns。
说明: CoreDNS 是 Kubernetes 的默认 DNS 服务。CoreDNS 设置标签 k8s-app=kube-dns,
以便能够在原来使用 kube-dns 的集群中工作。
启用 DNS 水平自动扩缩 在本节,我们创建一个 Deployment。Deployment 中的 Pod 运行一个基于
cluster-proportional-autoscaler-amd64 镜像的容器。
创建文件 dns-horizontal-autoscaler.yaml,内容如下所示:
apiVersion : apps/v1
kind : Deployment
metadata :
name : dns-autoscaler
namespace : kube-system
labels :
k8s-app : dns-autoscaler
spec :
selector :
matchLabels :
k8s-app : dns-autoscaler
template :
metadata :
labels :
k8s-app : dns-autoscaler
spec :
containers :
- name : autoscaler
image : k8s.gcr.io/cluster-proportional-autoscaler-amd64:1.6.0
resources :
requests :
cpu : 20m
memory : 10Mi
command :
- /cluster-proportional-autoscaler
- --namespace=kube-system
- --configmap=dns-autoscaler
- --target=<SCALE_TARGET>
# When cluster is using large nodes(with more cores), "coresPerReplica" should dominate.
# If using small nodes, "nodesPerReplica" should dominate.
- --default-params={"linear":{"coresPerReplica":256,"nodesPerReplica":16,"min":1}}
- --logtostderr=true
- --v=2
在文件中,将 <SCALE_TARGET> 替换成扩缩目标。
进入到包含配置文件的目录中,输入如下命令创建 Deployment:
kubectl apply -f dns-horizontal-autoscaler.yaml
一个成功的命令输出是:
deployment.apps/dns-autoscaler created
DNS 水平自动扩缩在已经启用了。
调优自动扩缩参数 验证 dns-autoscaler ConfigMap 是否存在:
kubectl get configmap --namespace= kube-system
输出类似于:
NAME DATA AGE
...
dns-autoscaler 1 ...
...
修改该 ConfigMap 中的数据:
kubectl edit configmap dns-autoscaler --namespace= kube-system
找到如下这行内容:
linear : '{"coresPerReplica":256,"min":1,"nodesPerReplica":16}'
根据需要修改对应的字段。“min” 字段表明 DNS 后端的最小数量。
实际后端的数量通过使用如下公式来计算:
replicas = max( ceil( cores * 1/coresPerReplica ) , ceil( nodes * 1/nodesPerReplica ) )
注意 coresPerReplica 和 nodesPerReplica 的值都是整数。
背后的思想是,当一个集群使用具有很多核心的节点时,由 coresPerReplica 来控制。
当一个集群使用具有较少核心的节点时,由 nodesPerReplica 来控制。
其它的扩缩模式也是支持的,详情查看
cluster-proportional-autoscaler 。
禁用 DNS 水平自动扩缩 有几个可供调优的 DNS 水平自动扩缩选项。具体使用哪个选项因环境而异。
选项 1:缩容 dns-autoscaler Deployment 至 0 个副本 该选项适用于所有场景。运行如下命令:
kubectl scale deployment --replicas= 0 dns-autoscaler --namespace= kube-system
输出如下所示:
deployment.apps/dns-autoscaler scaled
验证当前副本数为 0:
kubectl get rs --namespace= kube-system
输出内容中,在 DESIRED 和 CURRENT 列显示为 0:
NAME DESIRED CURRENT READY AGE
...
dns-autoscaler-6b59789fc8 0 0 0 ...
...
选项 2:删除 dns-autoscaler Deployment 如果 dns-autoscaler 为你所控制,也就说没有人会去重新创建它,可以选择此选项:
kubectl delete deployment dns-autoscaler --namespace= kube-system
输出内容如下所示:
deployment.apps "dns-autoscaler" deleted
选项 3:从主控节点删除 dns-autoscaler 清单文件 如果 dns-autoscaler 在插件管理器
的控制之下,并且具有操作 master 节点的写权限,可以使用此选项。
登录到主控节点,删除对应的清单文件。
dns-autoscaler 对应的路径一般为:
/etc/kubernetes/addons/dns-horizontal-autoscaler/dns-horizontal-autoscaler.yaml
当清单文件被删除后,插件管理器将删除 dns-autoscaler Deployment。
理解 DNS 水平自动扩缩工作原理 接下来 4.2.33 - 自定义 DNS 服务 本页说明如何配置 DNS Pod(s) ,以及定制集群中 DNS 解析过程。
准备开始
你必须拥有一个 Kubernetes 的集群,同时你的 Kubernetes 集群必须带有 kubectl 命令行工具。
如果你还没有集群,你可以通过 Minikube 构建一
个你自己的集群,或者你可以使用下面任意一个 Kubernetes 工具构建:
您的 Kubernetes 服务器版本必须不低于版本 v1.12.
要获知版本信息,请输入
kubectl version.
你的集群必须运行 CoreDNS 插件。
文档迁移到 CoreDNS
解释了如何使用 kubeadm 从 kube-dns 迁移到 CoreDNS。
介绍 DNS 是使用集群插件
管理器自动启动的内置的 Kubernetes 服务。
从 Kubernetes v1.12 开始,CoreDNS 是推荐的 DNS 服务器,取代了 kube-dns。 如果
你的集群原来使用 kube-dns,你可能部署的仍然是 kube-dns 而不是 CoreDNS。
说明: CoreDNS 和 kube-dns 的 Service 都在其 metadata.name 字段使用名字 kube-dns。
这是为了能够与依靠传统 kube-dns 服务名称来解析集群内部地址的工作负载具有更好的互操作性。
使用 kube-dns 作为服务名称可以抽离共有名称之后运行的是哪个 DNS 提供程序这一实现细节。
如果你在使用 Deployment 运行 CoreDNS,则该 Deployment 通常会向外暴露为一个具有
静态 IP 地址 Kubernetes 服务。
kubelet 使用 --cluster-dns=<DNS 服务 IP> 标志将 DNS 解析器的信息传递给每个容器。
DNS 名称也需要域名。 你可在 kubelet 中使用 --cluster-domain=<默认本地域名>
标志配置本地域名。
DNS 服务器支持正向查找(A 和 AAAA 记录)、端口发现(SRV 记录)、反向 IP 地址发现(PTR 记录)等。
更多信息,请参见Pod 和 服务的 DNS 。
如果 Pod 的 dnsPolicy 设置为 "default",则它将从 Pod 运行所在节点继承名称解析配置。
Pod 的 DNS 解析行为应该与节点相同。
但请参阅已知问题 。
如果你不想这样做,或者想要为 Pod 使用其他 DNS 配置,则可以
使用 kubelet 的 --resolv-conf 标志。 将此标志设置为 "" 可以避免 Pod 继承 DNS。
将其设置为有别于 /etc/resolv.conf 的有效文件路径可以设定 DNS 继承不同的配置。
CoreDNS CoreDNS 是通用的权威 DNS 服务器,可以用作集群 DNS,符合
DNS 规范 。
CoreDNS ConfigMap 选项 CoreDNS 是模块化且可插拔的 DNS 服务器,每个插件都为 CoreDNS 添加了新功能。
可以通过维护 Corefile ,即 CoreDNS 配置文件,
来定制其行为。 集群管理员可以修改 CoreDNS Corefile 的 ConfigMap,以更改服务发现的工作方式。
在 Kubernetes 中,CoreDNS 安装时使用如下默认 Corefile 配置。
apiVersion : v1
kind : ConfigMap
metadata :
name : coredns
namespace : kube-system
data :
Corefile : |
.:53 {
errors
health {
lameduck 5s
}
ready
kubernetes cluster.local in-addr.arpa ip6.arpa {
pods insecure
fallthrough in-addr.arpa ip6.arpa
ttl 30
}
prometheus :9153
forward . /etc/resolv.conf
cache 30
loop
reload
loadbalance
}
Corefile 配置包括以下 CoreDNS 插件 :
errors :错误记录到标准输出。
health :在 http://localhost:8080/health 处提供 CoreDNS 的健康报告。
ready :在端口 8181 上提供的一个 HTTP 末端,当所有能够
表达自身就绪的插件都已就绪时,在此末端返回 200 OK。
kubernetes :CoreDNS 将基于 Kubernetes 的服务和 Pod 的
IP 答复 DNS 查询。你可以在 CoreDNS 网站阅读更多细节 。
你可以使用 ttl 来定制响应的 TTL。默认值是 5 秒钟。TTL 的最小值可以是 0 秒钟,
最大值为 3600 秒。将 TTL 设置为 0 可以禁止对 DNS 记录进行缓存。
pods insecure 选项是为了与 kube-dns 向后兼容。你可以使用 pods verified 选项,该选项使得
仅在相同名称空间中存在具有匹配 IP 的 Pod 时才返回 A 记录。如果你不使用 Pod 记录,则可以使用
pods disabled 选项。
prometheus :CoreDNS 的度量指标值以
Prometheus 格式在 http://localhost:9153/metrics 上提供。forward : 不在 Kubernetes 集群域内的任何查询都将转发到
预定义的解析器 (/etc/resolv.conf).cache :启用前端缓存。loop :检测到简单的转发环,如果发现死循环,则中止 CoreDNS 进程。reload :允许自动重新加载已更改的 Corefile。
编辑 ConfigMap 配置后,请等待两分钟,以使更改生效。loadbalance :这是一个轮转式 DNS 负载均衡器,
它在应答中随机分配 A、AAAA 和 MX 记录的顺序。你可以通过修改 ConfigMap 来更改默认的 CoreDNS 行为。
使用 CoreDNS 配置存根域和上游域名服务器 CoreDNS 能够使用 forward 插件 配置存根域和上游域名服务器。
示例 如果集群操作员在 10.150.0.1 处运行了 Consul 域服务器,
且所有 Consul 名称都带有后缀 .consul.local。要在 CoreDNS 中对其进行配置,
集群管理员可以在 CoreDNS 的 ConfigMap 中创建加入以下字段。
consul.local:53 {
errors
cache 30
forward . 10.150.0.1
}
要显式强制所有非集群 DNS 查找通过特定的域名服务器(位于 172.16.0.1),可将 forward
指向该域名服务器,而不是 /etc/resolv.conf。
forward . 172.16.0.1
最终的包含默认的 Corefile 配置的 ConfigMap 如下所示:
apiVersion : v1
kind : ConfigMap
metadata :
name : coredns
namespace : kube-system
data :
Corefile : |
.:53 {
errors
health
kubernetes cluster.local in-addr.arpa ip6.arpa {
pods insecure
fallthrough in-addr.arpa ip6.arpa
}
prometheus :9153
forward . 172.16.0.1
cache 30
loop
reload
loadbalance
}
consul.local:53 {
errors
cache 30
forward . 10.150.0.1
}
工具 kubeadm 支持将 kube-dns ConfigMap 自动转换为 CoreDNS ConfigMap。
说明: 尽管 kube-dns 接受 FQDN(例如:ns.foo.com)作为存根域和名字服务器,CoreDNS 不支持此功能。
转换期间,CoreDNS 配置中将忽略所有的 FQDN 域名服务器。
CoreDNS 配置等同于 kube-dns CoreDNS 不仅仅提供 kube-dns 的功能。
为 kube-dns 创建的 ConfigMap 支持 StubDomains 和 upstreamNameservers 转换为 CoreDNS 中的 forward 插件。
同样,kube-dns 中的 Federations 插件会转换为 CoreDNS 中的 federation 插件。
示例 用于 kubedns 的此示例 ConfigMap 描述了 federations、stubdomains and upstreamnameservers:
apiVersion : v1
data :
federations : |
{"foo" : "foo.feddomain.com" }
stubDomains : |
{"abc.com" : ["1.2.3.4" ], "my.cluster.local" : ["2.3.4.5" ]}
upstreamNameservers : |
["8.8.8.8" , "8.8.4.4" ]
kind : ConfigMap
CoreDNS 中的等效配置将创建一个 Corefile:
针对 federations:
federation cluster.local {
foo foo.feddomain.com
}
针对 stubDomains:
abc.com:53 {
errors
cache 30
proxy . 1.2.3.4
}
my.cluster.local:53 {
errors
cache 30
proxy . 2.3.4.5
}
带有默认插件的完整 Corefile:
.:53 {
errors
health
kubernetes cluster.local in-addr.arpa ip6.arpa {
pods insecure
fallthrough in-addr.arpa ip6.arpa
}
federation cluster.local {
foo foo.feddomain.com
}
prometheus :9153
forward . 8.8.8.8 8.8.4.4
cache 30
}
abc.com:53 {
errors
cache 30
forward . 1.2.3.4
}
my.cluster.local:53 {
errors
cache 30
forward . 2.3.4.5
}
迁移到 CoreDNS 要从 kube-dns 迁移到 CoreDNS,此博客
提供了帮助用户将 kube-dns 替换为 CoreDNS。
集群管理员还可以使用部署脚本
进行迁移。
接下来 4.2.34 - 访问集群上运行的服务 本文展示了如何连接 Kubernetes 集群上运行的服务。
准备开始
你必须拥有一个 Kubernetes 的集群,同时你的 Kubernetes 集群必须带有 kubectl 命令行工具。
如果你还没有集群,你可以通过 Minikube 构建一
个你自己的集群,或者你可以使用下面任意一个 Kubernetes 工具构建:
要获知版本信息,请输入
kubectl version.
访问集群上运行的服务 在 Kubernetes 里,节点 、
Pod 和
服务 都有自己的 IP。
许多情况下,集群上的节点 IP、Pod IP 和某些服务 IP 是路由不可达的,
所以不能从集群之外访问它们,例如从你自己的台式机。
连接方式 你有多种可选方式从集群外连接节点、Pod 和服务:
通过公网 IP 访问服务使用类型为 NodePort 或 LoadBalancer 的服务,可以从外部访问它们。
请查阅服务 和
kubectl expose 文档。 取决于你的集群环境,你可以仅把服务暴露在你的企业网络环境中,也可以将其暴露在
因特网上。需要考虑暴露的服务是否安全,它是否有自己的用户认证? 将 Pod 放置于服务背后。如果要访问一个副本集合中特定的 Pod,例如用于调试目的,
请给 Pod 指定一个独特的标签并创建一个新服务选择该标签。 大部分情况下,都不需要应用开发者通过节点 IP 直接访问节点。 通过 Proxy 动词访问服务、节点或者 Pod在访问远程服务之前,利用 API 服务器执行身份认证和鉴权。
如果你的服务不够安全,无法暴露到因特网中,或者需要访问节点 IP 上的端口,
又或者出于调试目的,可使用这种方式。 代理可能给某些应用带来麻烦 此方式仅适用于 HTTP/HTTPS 进一步的描述在这里 从集群中的 node 或者 pod 访问。 从集群中的一个节点或 Pod 访问运行一个 Pod,然后使用
kubectl exec
连接到它的 Shell。从那个 Shell 连接其他的节点、Pod 和 服务 某些集群可能允许你 SSH 到集群中的节点。你可能可以从那儿访问集群服务。
这是一个非标准的方式,可能在一些集群上能工作,但在另一些上却不能。
浏览器和其他工具可能已经安装也可能没有安装。集群 DNS 可能不会正常工作。 发现内置服务 典型情况下,kube-system 名字空间中会启动集群的几个服务。
使用 kubectl cluster-info 命令获取这些服务的列表:
输出类似于:
Kubernetes master is running at https://104.197.5.247
elasticsearch-logging is running at https://104.197.5.247/api/v1/namespaces/kube-system/services/elasticsearch-logging/proxy
kibana-logging is running at https://104.197.5.247/api/v1/namespaces/kube-system/services/kibana-logging/proxy
kube-dns is running at https://104.197.5.247/api/v1/namespaces/kube-system/services/kube-dns/proxy
grafana is running at https://104.197.5.247/api/v1/namespaces/kube-system/services/monitoring-grafana/proxy
heapster is running at https://104.197.5.247/api/v1/namespaces/kube-system/services/monitoring-heapster/proxy
这一输出显示了用 proxy 动词访问每个服务时可用的 URL。例如,此集群
(使用 Elasticsearch)启用了集群层面的日志。如果提供合适的凭据,可以通过
https://104.197.5.247/api/v1/namespaces/kube-system/services/elasticsearch-logging/proxy/
访问,或通过一个 kubectl proxy 来访问:
http://localhost:8080/api/v1/namespaces/kube-system/services/elasticsearch-logging/proxy/。
手动构建 API 服务器代理 URLs 如前所述,你可以使用 kubectl cluster-info 命令取得服务的代理 URL。
为了创建包含服务末端、后缀和参数的代理 URLs,你可以简单地在服务的代理 URL 中添加:
http://kubernetes_master_address/api/v1/namespaces/namespace_name/services/service_name[:port_name]/proxy
如果还没有为你的端口指定名称,你可以不用在 URL 中指定 port_name 。
示例 通过 Web 浏览器访问集群中运行的服务 你或许能够将 API 服务器代理的 URL 放入浏览器的地址栏,然而:
Web 服务器通常不能传递令牌,所以你可能需要使用基本(密码)认证。
API 服务器可以配置为接受基本认证,但你的集群可能并没有这样配置。 某些 Web 应用可能无法工作,特别是那些使用客户端 Javascript 构造 URL 的
应用,所构造的 URL 可能并不支持代理路径前缀。 4.2.35 - 调试 DNS 问题 这篇文章提供了一些关于 DNS 问题诊断的方法。
准备开始 你必须拥有一个 Kubernetes 的集群,同时你的 Kubernetes 集群必须带有 kubectl 命令行工具。
如果你还没有集群,你可以通过 Minikube 构建一
个你自己的集群,或者你可以使用下面任意一个 Kubernetes 工具构建:
你的集群必须使用了 CoreDNS 插件
或者其前身,kube-dns。
您的 Kubernetes 服务器版本必须不低于版本 v1.6.
要获知版本信息,请输入
kubectl version.
创建一个简单的 Pod 作为测试环境 apiVersion : v1
kind : Pod
metadata :
name : dnsutils
namespace : default
spec :
containers :
- name : dnsutils
image : gcr.io/kubernetes-e2e-test-images/dnsutils:1.3
command :
- sleep
- "3600"
imagePullPolicy : IfNotPresent
restartPolicy : Always
使用上面的清单来创建一个 Pod:
kubectl apply -f https://k8s.io/examples/admin/dns/dnsutils.yaml
pod/dnsutils created
验证其状态:
kubectl get pods dnsutils
NAME READY STATUS RESTARTS AGE
dnsutils 1/1 Running 0 <some-time>
一旦 Pod 处于运行状态,你就可以在该环境里执行 nslookup。
如果你看到类似下列的内容,则表示 DNS 是正常运行的。
kubectl exec -i -t dnsutils -- nslookup kubernetes.default
Server: 10.0.0.10
Address 1: 10.0.0.10
Name: kubernetes.default
Address 1: 10.0.0.1
如果 nslookup 命令执行失败,请检查下列内容:
先检查本地的 DNS 配置 查看 resolv.conf 文件的内容
(阅读从节点继承 DNS 配置 和
后文的已知问题 ,获取更多信息)
kubectl exec -ti dnsutils -- cat /etc/resolv.conf
验证 search 和 nameserver 的配置是否与下面的内容类似
(注意 search 根据不同的云提供商可能会有所不同):
search default.svc.cluster.local svc.cluster.local cluster.local google.internal c.gce_project_id.internal
nameserver 10.0.0.10
options ndots:5
下列错误表示 CoreDNS (或 kube-dns)插件或者相关服务出现了问题:
kubectl exec -i -t dnsutils -- nslookup kubernetes.default
输出为:
Server: 10.0.0.10
Address 1: 10.0.0.10
nslookup: can't resolve 'kubernetes.default'
或者
Server: 10.0.0.10
Address 1: 10.0.0.10 kube-dns.kube-system.svc.cluster.local
nslookup: can't resolve 'kubernetes.default'
检查 DNS Pod 是否运行 使用 kubectl get pods 命令来验证 DNS Pod 是否运行。
kubectl get pods --namespace= kube-system -l k8s-app= kube-dns
NAME READY STATUS RESTARTS AGE
...
coredns-7b96bf9f76-5hsxb 1/1 Running 0 1h
coredns-7b96bf9f76-mvmmt 1/1 Running 0 1h
...
说明: 对于 CoreDNS 和 kube-dns 部署而言,标签 k8s-app 的值都应该是 kube-dns。
如果你发现没有 CoreDNS Pod 在运行,或者该 Pod 的状态是 failed 或者 completed,
那可能这个 DNS 插件在您当前的环境里并没有成功部署,你将需要手动去部署它。
检查 DNS Pod 里的错误 使用 kubectl logs 命令来查看 DNS 容器的日志信息。
kubectl logs --namespace= kube-system -l k8s-app= kube-dns
下列是一个正常运行的 CoreDNS 日志信息:
.:53
2018/08/15 14:37:17 [INFO] CoreDNS-1.2.2
2018/08/15 14:37:17 [INFO] linux/amd64, go1.10.3, 2e322f6
CoreDNS-1.2.2
linux/amd64, go1.10.3, 2e322f6
2018/08/15 14:37:17 [INFO] plugin/reload: Running configuration MD5 = 24e6c59e83ce706f07bcc82c31b1ea1c
查看是否日志中有一些可疑的或者意外的消息。
检查是否启用了 DNS 服务 使用 kubectl get service 命令来检查 DNS 服务是否已经启用。
kubectl get svc --namespace= kube-system
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
...
kube-dns ClusterIP 10.0.0.10 <none> 53/UDP,53/TCP 1h
...
说明: 不管是 CoreDNS 还是 kube-dns,这个服务的名字都会是 kube-dns 。
如果你已经创建了 DNS 服务,或者该服务应该是默认自动创建的但是它并没有出现,
请阅读调试服务
来获取更多信息。
DNS 的端点公开了吗? 你可以使用 kubectl get endpoints 命令来验证 DNS 的端点是否公开了。
kubectl get ep kube-dns --namespace= kube-system
NAME ENDPOINTS AGE
kube-dns 10.180.3.17:53,10.180.3.17:53 1h
如果你没看到对应的端点,请阅读
调试服务 的端点部分。
若需要了解更多的 Kubernetes DNS 例子,请在 Kubernetes GitHub 仓库里查看
cluster-dns 示例 。
DNS 查询有被接收或者执行吗? 你可以通过给 CoreDNS 的配置文件(也叫 Corefile)添加 log 插件来检查查询是否被正确接收。
CoreDNS 的 Corefile 被保存在一个叫 coredns 的 ConfigMap 里,使用下列命令来编辑它:
kubectl -n kube-system edit configmap coredns
然后按下面的例子给 Corefile 添加 log。
apiVersion : v1
kind : ConfigMap
metadata :
name : coredns
namespace : kube-system
data :
Corefile : |
.:53 {
log
errors
health
kubernetes cluster.local in-addr.arpa ip6.arpa {
pods insecure
upstream
fallthrough in-addr.arpa ip6.arpa
}
prometheus :9153
forward . /etc/resolv.conf
cache 30
loop
reload
loadbalance
}
保存这些更改后,你可能会需要等待一到两分钟让 Kubernetes 把这些更改应用到
CoreDNS 的 Pod 里。
接下来,发起一些查询并依照前文所述查看日志信息,如果 CoreDNS 的 Pod 接收到这些查询,
你将可以在日志信息里看到它们。
下面是日志信息里的查询例子:
.:53
2018/08/15 14:37:15 [INFO] CoreDNS-1.2.0
2018/08/15 14:37:15 [INFO] linux/amd64, go1.10.3, 2e322f6
CoreDNS-1.2.0
linux/amd64, go1.10.3, 2e322f6
2018/09/07 15:29:04 [INFO] plugin/reload: Running configuration MD5 = 162475cdf272d8aa601e6fe67a6ad42f
2018/09/07 15:29:04 [INFO] Reloading complete
172.17.0.18:41675 - [07/Sep/2018:15:29:11 +0000] 59925 "A IN kubernetes.default.svc.cluster.local. udp 54 false 512" NOERROR qr,aa,rd,ra 106 0.000066649s
已知问题 有些 Linux 发行版本(比如 Ubuntu)默认使用一个本地的 DNS 解析器(systemd-resolved)。
systemd-resolved 会用一个存根文件(Stub File)来覆盖 /etc/resolv.conf 内容,
从而可能在上游服务器中解析域名产生转发环(forwarding loop)。 这个问题可以通过手动指定
kubelet 的 --resolv-conf 标志为正确的 resolv.conf(如果是 systemd-resolved,
则这个文件路径为 /run/systemd/resolve/resolv.conf)来解决。
kubeadm 会自动检测 systemd-resolved 并对应的更改 kubelet 的命令行标志。
Kubernetes 的安装并不会默认配置节点的 resolv.conf 文件来使用集群的 DNS 服务,因为这个配置对于不同的发行版本是不一样的。这个问题应该迟早会被解决的。
Linux 的 libc 限制 nameserver 只能有三个记录。不仅如此,对于 glibc-2.17-222
之前的版本(参见此 Issue 了解新版本的更新 ),search 的记录不能超过 6 个
( 详情请查阅这个 2005 年的 bug )。
Kubernetes 需要占用一个 nameserver 记录和三个search记录。
这意味着如果一个本地的安装已经使用了三个 nameserver 或者使用了超过三个
search 记录,而你的 glibc 版本也在有问题的版本列表中,那么有些配置很可能会丢失。
为了绕过 DNS nameserver 个数限制,节点可以运行 dnsmasq,以提供更多的
nameserver 记录。你也可以使用kubelet 的 --resolv-conf 标志来解决这个问题。
要想修复 DNS search 记录个数限制问题,可以考虑升级你的 Linux 发行版本,或者
升级 glibc 到一个不再受此困扰的版本。
如果你使用 Alpine 3.3 或更早版本作为你的基础镜像,DNS 可能会由于 Alpine 中
一个已知的问题导致无法正常工作。
请查看这里 获取更多信息。
接下来 4.2.36 - 通过名字空间共享集群 本页展示如何查看、使用和删除名字空间 。
本页同时展示如何使用 Kubernetes 名字空间来划分集群。
准备开始 查看名字空间 列出集群中现有的名字空间: NAME STATUS AGE
default Active 11d
kube-system Active 11d
kube-public Active 11d
初始状态下,Kubernetes 具有三个名字空间:
default 无名字空间对象的默认名字空间kube-system 由 Kubernetes 系统创建的对象的名字空间kube-public 自动创建且被所有用户可读的名字空间(包括未经身份认证的)。此名字空间通常在某些资源在整个集群中可见且可公开读取时被集群使用。此名字空间的公共方面只是一个约定,而不是一个必要条件。你还可以通过下列命令获取特定名字空间的摘要:
kubectl get namespaces <name>
或用下面的命令获取详细信息:
kubectl describe namespaces <name>
Name: default
Labels: <none>
Annotations: <none>
Status: Active
No resource quota.
Resource Limits
Type Resource Min Max Default
---- -------- --- --- ---
Container cpu - - 100m
请注意,这些详情同时显示了资源配额(如果存在)以及资源限制区间。
资源配额跟踪并聚合 Namespace 中资源的使用情况,并允许集群运营者定义 Namespace 可能消耗的 Hard 资源使用限制。
限制区间定义了单个实体在一个 Namespace 中可使用的最小/最大资源量约束。
参阅 准入控制: 限制区间
名字空间可以处于下列两个阶段中的一个:
Active 名字空间正在被使用中Terminating 名字空间正在被删除,且不能被用于新对象。参见设计文档 查看更多细节。
创建名字空间 说明: 避免使用前缀 kube- 创建名字空间,因为它是为 Kubernetes 系统名字空间保留的。
新建一个名为 my-namespace.yaml 的 YAML 文件,并写入下列内容:
apiVersion : v1
kind : Namespace
metadata :
name : <insert-namespace-name-here>
然后运行:
kubectl create -f ./my-namespace.yaml
或者,你可以使用下面的命令创建名字空间:
kubectl create namespace <insert-namespace-name-here>
请注意,名字空间的名称必须是一个合法的
DNS 标签 。
可选字段 finalizers 允许观察者们在名字空间被删除时清除资源。记住如果指定了一个不存在的终结器,名字空间仍会被创建,但如果用户试图删除它,它将陷入 Terminating 状态。
更多有关 finalizers 的信息请查阅 设计文档 中名字空间部分。
删除名字空间 删除名字空间使用命令:
kubectl delete namespaces <insert-some-namespace-name>
警告: 这会删除名字空间下的 所有内容 !
删除是异步的,所以有一段时间你会看到名字空间处于 Terminating 状态。
使用 Kubernetes 名字空间细分你的集群 理解 default 名字空间
默认情况下,Kubernetes 集群会在配置集群时实例化一个 default 名字空间,用以存放集群所使用的默认
Pods、Services 和 Deployments 集合。
假设你有一个新的集群,你可以通过执行以下操作来内省可用的名字空间
NAME STATUS AGE
default Active 13m
创建新的名字空间
在本练习中,我们将创建两个额外的 Kubernetes 名字空间来保存我们的内容。
在某组织使用共享的 Kubernetes 集群进行开发和生产的场景中:
开发团队希望在集群中维护一个空间,以便他们可以查看用于构建和运行其应用程序的 Pods、Services
和 Deployments 列表。在这个空间里,Kubernetes 资源被自由地加入或移除,
对谁能够或不能修改资源的限制被放宽,以实现敏捷开发。
运维团队希望在集群中维护一个空间,以便他们可以强制实施一些严格的规程,
对谁可以或不可以操作运行生产站点的 Pods、Services 和 Deployments 集合进行控制。
该组织可以遵循的一种模式是将 Kubernetes 集群划分为两个名字空间:development 和 production。
让我们创建两个新的名字空间来保存我们的工作。
使用 kubectl 创建 development 名字空间。
kubectl create -f https://k8s.io/examples/admin/namespace-dev.json
让我们使用 kubectl 创建 production 名字空间。
kubectl create -f https://k8s.io/examples/admin/namespace-prod.json
为了确保一切正常,列出集群中的所有名字空间。
kubectl get namespaces --show-labels
NAME STATUS AGE LABELS
default Active 32m <none>
development Active 29s name=development
production Active 23s name=production
在每个名字空间中创建 pod
Kubernetes 名字空间为集群中的 Pods、Services 和 Deployments 提供了作用域。
与一个名字空间交互的用户不会看到另一个名字空间中的内容。
为了演示这一点,让我们在 development 名字空间中启动一个简单的 Deployment 和 Pod。
kubectl create deployment snowflake --image= k8s.gcr.io/serve_hostname -n= development
kubectl scale deployment snowflake --replicas= 2 -n= development
我们刚刚创建了一个副本个数为 2 的 Deployment,运行名为 snowflake 的
Pod,其中包含一个仅负责提供主机名的基本容器。
kubectl get deployment -n= development
NAME READY UP-TO-DATE AVAILABLE AGE
snowflake 2/2 2 2 2m
kubectl get pods -l app = snowflake -n= development
NAME READY STATUS RESTARTS AGE
snowflake-3968820950-9dgr8 1/1 Running 0 2m
snowflake-3968820950-vgc4n 1/1 Running 0 2m
看起来还不错,开发人员能够做他们想做的事,而且他们不必担心会影响到
production 名字空间下面的内容。
让我们切换到 production 名字空间,展示一下一个名字空间中的资源是如何对
另一个名字空间隐藏的。
名字空间 production 应该是空的,下面的命令应该不会返回任何东西。
kubectl get deployment -n= production
kubectl get pods -n= production
生产环境下一般以养牛的方式运行负载,所以让我们创建一些 Cattle(牛)Pod。
kubectl create deployment cattle --image= k8s.gcr.io/serve_hostname -n= production
kubectl scale deployment cattle --replicas= 5 -n= production
kubectl get deployment -n= production
NAME READY UP-TO-DATE AVAILABLE AGE
cattle 5/5 5 5 10s
kubectl get pods -l app = cattle -n= production
NAME READY STATUS RESTARTS AGE
cattle-2263376956-41xy6 1/1 Running 0 34s
cattle-2263376956-kw466 1/1 Running 0 34s
cattle-2263376956-n4v97 1/1 Running 0 34s
cattle-2263376956-p5p3i 1/1 Running 0 34s
cattle-2263376956-sxpth 1/1 Running 0 34s
此时,应该很清楚的展示了用户在一个名字空间中创建的资源对另一个名字空间是隐藏的。
随着 Kubernetes 中的策略支持的发展,我们将扩展此场景,以展示如何为每个名字空间提供不同的授权规则。
理解使用名字空间的动机 单个集群应该能满足多个用户及用户组的需求(以下称为 “用户社区”)。
Kubernetes 名字空间 帮助不同的项目、团队或客户去共享 Kubernetes 集群。
名字空间通过以下方式实现这点:
为名字 设置作用域. 为集群中的部分资源关联鉴权和策略的机制。 使用多个名字空间是可选的。
每个用户社区都希望能够与其他社区隔离开展工作。
每个用户社区都有自己的:
资源(pods、服务、 副本控制器等等) 策略(谁能或不能在他们的社区里执行操作) 约束(该社区允许多少配额,等等) 集群运营者可以为每个唯一用户社区创建名字空间。
名字空间为下列内容提供唯一的作用域:
命名资源(避免基本的命名冲突) 将管理权限委派给可信用户 限制社区资源消耗的能力 用例包括:
作为集群运营者, 我希望能在单个集群上支持多个用户社区。 作为集群运营者,我希望将集群分区的权限委派给这些社区中的受信任用户。 作为集群运营者,我希望能限定每个用户社区可使用的资源量,以限制对使用同一集群的其他用户社区的影响。 作为群集用户,我希望与我的用户社区相关的资源进行交互,而与其他用户社区在该集群上执行的操作无关。 理解名字空间和 DNS 当你创建服务 时,Kubernetes
会创建相应的 DNS 条目 。
此条目的格式为 <服务名称>.<名字空间名称>.svc.cluster.local。
这意味着如果容器只使用 <服务名称>,它将解析为名字空间本地的服务。
这对于在多个名字空间(如开发、暂存和生产)中使用相同的配置非常有用。
如果要跨名字空间访问,则需要使用完全限定的域名(FQDN)。
接下来 4.2.37 - 通过配置文件设置 Kubelet 参数 FEATURE STATE: Kubernetes v1.10 [beta]
通过保存在硬盘的配置文件设置 kubelet 的部分配置参数,这可以作为命令行参数的替代。
此功能在 v1.10 中为 beta 版。
建议通过配置文件的方式提供参数,因为这样可以简化节点部署和配置管理。
准备开始 需要安装 1.10 或更高版本的 kubelet 可执行文件,才能使用此 beta 功能。 创建配置文件 KubeletConfiguration 结构体定义了可以通过文件配置的 Kubelet 配置子集,
该结构体在 这里(v1beta1)
可以找到。
配置文件必须是这个结构体中参数的 JSON 或 YAML 表现形式。
确保 kubelet 可以读取该文件。
下面是一个 Kubelet 配置文件示例:
kind : KubeletConfiguration
apiVersion : kubelet.config.k8s.io/v1beta1
evictionHard :
memory.available : "200Mi"
在这个示例中, 当可用内存低于 200Mi 时, kubelet 将会开始驱逐 Pods。
没有声明的其余配置项都将使用默认值,除非使用命令行参数来重载。
命令行中的参数将会覆盖配置文件中的对应值。
作为一个小技巧,你可以从活动节点生成配置文件,相关方法请查看
重新配置活动集群节点的 kubelet 。
启动通过配置文件配置的 Kubelet 进程 启动 Kubelet 需要将 --config 参数设置为 Kubelet 配置文件的路径。Kubelet 将从此文件加载其配置。
请注意,命令行参数与配置文件有相同的值时,就会覆盖配置文件中的该值。
这有助于确保命令行 API 的向后兼容性。
请注意,kubelet 配置文件中的相对文件路径是相对于 kubelet 配置文件的位置解析的,
而命令行参数中的相对路径是相对于 kubelet 的当前工作目录解析的。
请注意,命令行参数和 Kubelet 配置文件的某些默认值不同。
如果设置了 --config,并且没有通过命令行指定值,则 KubeletConfiguration
版本的默认值生效。在上面的例子中,version 是 kubelet.config.k8s.io/v1beta1。
与动态 Kubelet 配置的关系 如果你正在使用动态 kubelet 配置 特性,
那么自动回滚机制将认为通过 --config 提供的配置与覆盖这些值的任何参数的组合是
"最后已知正常(last known good)" 的配置。
4.2.38 - 配置 API 对象配额 本文讨论如何为 API 对象配置配额,包括 PersistentVolumeClaim 和 Service。
配额限制了可以在命名空间中创建的特定类型对象的数量。
你可以在 ResourceQuota 对象中指定配额。
准备开始
你必须拥有一个 Kubernetes 的集群,同时你的 Kubernetes 集群必须带有 kubectl 命令行工具。
如果你还没有集群,你可以通过 Minikube 构建一
个你自己的集群,或者你可以使用下面任意一个 Kubernetes 工具构建:
要获知版本信息,请输入
kubectl version.
创建命名空间 创建一个命名空间以便本例中创建的资源和集群中的其余部分相隔离。
kubectl create namespace quota-object-example
创建 ResourceQuota 下面是一个 ResourceQuota 对象的配置文件:
apiVersion : v1
kind : ResourceQuota
metadata :
name : object-quota-demo
spec :
hard :
persistentvolumeclaims : "1"
services.loadbalancers : "2"
services.nodeports : "0"
创建 ResourceQuota:
kubectl apply -f https://k8s.io/examples/admin/resource/quota-objects.yaml --namespace= quota-object-example
查看 ResourceQuota 的详细信息:
kubectl get resourcequota object-quota-demo --namespace= quota-object-example --output= yaml
输出结果表明在 quota-object-example 命名空间中,至多只能有一个 PersistentVolumeClaim,
最多两个 LoadBalancer 类型的服务,不能有 NodePort 类型的服务。
status :
hard :
persistentvolumeclaims : "1"
services.loadbalancers : "2"
services.nodeports : "0"
used :
persistentvolumeclaims : "0"
services.loadbalancers : "0"
services.nodeports : "0"
创建 PersistentVolumeClaim 下面是一个 PersistentVolumeClaim 对象的配置文件:
apiVersion : v1
kind : PersistentVolumeClaim
metadata :
name : pvc-quota-demo
spec :
storageClassName : manual
accessModes :
- ReadWriteOnce
resources :
requests :
storage : 3Gi
创建 PersistentVolumeClaim:
kubectl apply -f https://k8s.io/examples/admin/resource/quota-objects-pvc.yaml --namespace= quota-object-example
确认已创建完 PersistentVolumeClaim:
kubectl get persistentvolumeclaims --namespace= quota-object-example
输出信息表明 PersistentVolumeClaim 存在并且处于 Pending 状态:
NAME STATUS
pvc-quota-demo Pending
尝试创建第二个 PersistentVolumeClaim 下面是第二个 PersistentVolumeClaim 的配置文件:
apiVersion : v1
kind : PersistentVolumeClaim
metadata :
name : pvc-quota-demo-2
spec :
storageClassName : manual
accessModes :
- ReadWriteOnce
resources :
requests :
storage : 4Gi
尝试创建第二个 PersistentVolumeClaim:
kubectl create -f https://k8s.io/examples/admin/resource/quota-objects-pvc-2.yaml --namespace= quota-object-example
输出信息表明第二个 PersistentVolumeClaim 没有创建成功,因为这会超出命名空间的配额。
persistentvolumeclaims "pvc-quota-demo-2" is forbidden:
exceeded quota: object-quota-demo, requested: persistentvolumeclaims=1,
used: persistentvolumeclaims=1, limited: persistentvolumeclaims=1
说明 下面这些字符串可被用来标识那些能被配额限制的 API 资源:
String API Object "pods" Pod "services" Service "replicationcontrollers" ReplicationController "resourcequotas" ResourceQuota "secrets" Secret "configmaps" ConfigMap "persistentvolumeclaims" PersistentVolumeClaim "services.nodeports" Service of type NodePort "services.loadbalancers" Service of type LoadBalancer
清理 删除你的命名空间:
kubectl delete namespace quota-object-example
接下来 集群管理员参考 应用开发者参考 4.2.39 - 配置资源不足时的处理方式 本页介绍如何使用 kubelet 配置资源不足时的处理方式。
当可用计算资源较少时,kubelet需要保证节点稳定性。
这在处理如内存和硬盘之类的不可压缩资源时尤为重要。
如果任意一种资源耗尽,节点将会变得不稳定。
驱逐信号 kubelet 支持按照以下表格中描述的信号触发驱逐决定。
每个信号的值在 description 列描述,基于 kubelet 摘要 API。
驱逐信号 描述 memory.availablememory.available := node.status.capacity[memory] - node.stats.memory.workingSetnodefs.availablenodefs.available := node.stats.fs.availablenodefs.inodesFreenodefs.inodesFree := node.stats.fs.inodesFreeimagefs.availableimagefs.available := node.stats.runtime.imagefs.availableimagefs.inodesFreeimagefs.inodesFree := node.stats.runtime.imagefs.inodesFreepid.availablepid.available := node.stats.rlimit.maxpid - node.stats.rlimit.curproc
上面的每个信号都支持字面值或百分比的值。基于百分比的值的计算与每个信号对应的总容量相关。
memory.available 的值从 cgroupfs 获取,而不是通过类似 free -m 的工具。
这很重要,因为 free -m 不能在容器中工作,并且如果用户使用了
节点可分配资源
特性,资源不足的判定将同时在本地 cgroup 层次结构的终端用户 Pod 部分和根节点做出。
这个脚本
复现了与 kubelet 计算 memory.available 相同的步骤。
kubelet 将 inactive_file(意即活动 LRU 列表上基于文件后端的内存字节数)从计算中排除,
因为它假设内存在出现压力时将被回收。
kubelet 只支持两种文件系统分区。
nodefs 文件系统,kubelet 将其用于卷和守护程序日志等。imagefs 文件系统,容器运行时用于保存镜像和容器可写层。imagefs 可选。kubelet 使用 cAdvisor 自动发现这些文件系统。
kubelet 不关心其它文件系统。当前不支持配置任何其它类型。
例如,在专用 filesytem 中存储卷和日志是 不可以 的。
在将来的发布中,kubelet将废除当前存在的
垃圾回收
机制,这种机制目前支持将驱逐操作作为对磁盘压力的响应。
驱逐阈值 kubelet支持指定驱逐阈值,用于触发 kubelet 回收资源。
每个阈值形式如下:
[eviction-signal][operator][quantity]
合法的 eviction-signal 标志如上所示。 operator 是所需的关系运算符,例如 <。quantity 是驱逐阈值值标志,例如 1Gi。合法的标志必须匹配 Kubernetes 使用的数量表示。
驱逐阈值也可以使用 % 标记表示百分比。举例说明,如果一个节点有 10Gi 内存,希望在可用内存下降到 1Gi 以下时引起驱逐操作,
则驱逐阈值可以使用下面任意一种方式指定(但不是两者同时)。
memory.available<10%memory.available<1Gi软驱逐阈值 软驱逐阈值使用一对由驱逐阈值和管理员必须指定的宽限期组成的配置对。在超过宽限期前,kubelet不会采取任何动作回收和驱逐信号关联的资源。如果没有提供宽限期,kubelet启动时将报错。
此外,如果达到了软驱逐阈值,操作员可以指定从节点驱逐 pod 时,在宽限期内允许结束的 pod 的最大数量。
如果指定了 pod.Spec.TerminationGracePeriodSeconds 值,
kubelet 将使用它和宽限期二者中较小的一个。
如果没有指定,kubelet将立即终止 pod,而不会优雅结束它们。
软驱逐阈值的配置支持下列标记:
eviction-soft 描述了驱逐阈值的集合(例如 memory.available<1.5Gi),如果在宽限期之外满足条件将触发 pod 驱逐。eviction-soft-grace-period 描述了驱逐宽限期的集合(例如 memory.available=1m30s),对应于在驱逐 pod 前软驱逐阈值应该被控制的时长。eviction-max-pod-grace-period 描述了当满足软驱逐阈值并终止 pod 时允许的最大宽限期值(秒数)。硬驱逐阈值 硬驱逐阈值没有宽限期,一旦察觉,kubelet 将立即采取行动回收关联的短缺资源。
如果满足硬驱逐阈值,kubelet 将立即结束 Pod 而不是体面地终止它们。
硬驱逐阈值的配置支持下列标记:
eviction-hard 描述了驱逐阈值的集合(例如 memory.available<1Gi),如果满足条件将触发 Pod 驱逐。kubelet 有如下所示的默认硬驱逐阈值:
memory.available<100Minodefs.available<10%imagefs.available<15%在Linux节点上,默认值还包括 nodefs.inodesFree<5%。
驱逐监控时间间隔 kubelet 根据其配置的整理时间间隔计算驱逐阈值。
housekeeping-interval 是容器管理时间间隔。节点状态 kubelet 会将一个或多个驱逐信号映射到对应的节点状态。
如果满足硬驱逐阈值,或者满足独立于其关联宽限期的软驱逐阈值时,kubelet将报告节点处于压力下的状态。
下列节点状态根据相应的驱逐信号定义。
节点状态 驱逐信号 描述 MemoryPressurememory.available节点上可用内存量达到逐出阈值 DiskPressurenodefs.available, nodefs.inodesFree, imagefs.available, 或 imagefs.inodesFree节点或者节点的根文件系统或镜像文件系统上可用磁盘空间和 i 节点个数达到逐出阈值 PIDPressurepid.available在(Linux)节点上的可用进程标识符已降至驱逐阈值以下
kubelet 将以 --node-status-update-frequency 指定的频率连续报告节点状态更新,其默认值为 10s。
节点状态振荡 如果节点在软驱逐阈值的上下振荡,但没有超过关联的宽限期时,将引起对应节点的状态持续在
true 和 false 间跳变,并导致不好的调度结果。
为了防止这种振荡,可以定义下面的标志,用于控制 kubelet 从压力状态中退出之前必须等待的时间。
eviction-pressure-transition-period 是 kubelet 从压力状态中退出之前必须等待的时长。kubelet 将确保在设定的时间段内没有发现和指定压力条件相对应的驱逐阈值被满足时,才会将状态变回 false。
回收节点层级资源 如果满足驱逐阈值并超过了宽限期,kubelet将启动回收压力资源的过程,直到它发现低于设定阈值的信号为止。
kubelet 将尝试在驱逐终端用户 pod 前回收节点层级资源。
发现磁盘压力时,如果节点针对容器运行时配置有独占的 imagefs,kubelet回收节点层级资源的方式将会不同。
使用 imagefs 如果 nodefs 文件系统满足驱逐阈值,kubelet通过驱逐 pod 及其容器来释放磁盘空间。
如果 imagefs 文件系统满足驱逐阈值,kubelet通过删除所有未使用的镜像来释放磁盘空间。
未使用 imagefs 如果 nodefs 满足驱逐阈值,kubelet将以下面的顺序释放磁盘空间:
删除停止运行的 pod/container 删除全部没有使用的镜像 驱逐最终用户的 pod 如果 kubelet 在节点上无法回收足够的资源,kubelet将开始驱逐 pod。
kubelet 首先根据他们对短缺资源的使用是否超过请求来排除 pod 的驱逐行为,
然后通过优先级 ,
然后通过相对于 pod 的调度请求消耗急需的计算资源。
kubelet 按以下顺序对要驱逐的 pod 排名:
BestEffort 或 Burstable,其对短缺资源的使用超过了其请求,此类 pod 按优先级排序,然后使用高于请求。Guaranteed pod 和 Burstable pod,其使用率低于请求,最后被驱逐。
Guaranteed Pod 只有为所有的容器指定了要求和限制并且它们相等时才能得到保证。
由于另一个 Pod 的资源消耗,这些 Pod 保证永远不会被驱逐。
如果系统守护进程(例如 kubelet、docker、和 journald)消耗的资源多于通过
system-reserved 或 kube-reserved 分配保留的资源,并且该节点只有 Guaranteed 或
Burstable Pod 使用少于剩余的请求,然后节点必须选择驱逐这样的 Pod
以保持节点的稳定性并限制意外消耗对其他 pod 的影响。
在这种情况下,它将首先驱逐优先级最低的 pod。必要时,kubelet会在遇到 DiskPressure 时逐个驱逐 Pod 来回收磁盘空间。
如果 kubelet 响应 inode 短缺,它会首先驱逐服务质量最低的 Pod 来回收 inodes。
如果 kubelet 响应缺少可用磁盘,它会将 Pod 排在服务质量范围内,该服务会消耗大量的磁盘并首先结束这些磁盘。
使用 imagefs 如果是 nodefs 触发驱逐,kubelet将按 nodefs 用量 - 本地卷 + pod 的所有容器日志的总和对其排序。
如果是 imagefs 触发驱逐,kubelet将按 pod 所有可写层的用量对其进行排序。
未使用 imagefs 如果是 nodefs 触发驱逐,kubelet会根据磁盘的总使用情况对 pod 进行排序 - 本地卷 + 所有容器的日志及其可写层。
最小驱逐回收 在某些场景,驱逐 pod 会导致回收少量资源。这将导致 kubelet 反复碰到驱逐阈值。除此之外,对如 disk 这类资源的驱逐时比较耗时的。
为了减少这类问题,kubelet可以为每个资源配置一个 minimum-reclaim。
当 kubelet 发现资源压力时,kubelet将尝试至少回收驱逐阈值之下 minimum-reclaim 数量的资源。
例如使用下面的配置:
--eviction-hard=memory.available<500Mi,nodefs.available<1Gi,imagefs.available<100Gi
--eviction-minimum-reclaim="memory.available=0Mi,nodefs.available=500Mi,imagefs.available=2Gi"`
如果 memory.available 驱逐阈值被触发,kubelet 将保证 memory.available 至少为 500Mi。
对于 nodefs.available,kubelet 将保证 nodefs.available 至少为 1.5Gi。
对于 imagefs.available,kubelet 将保证 imagefs.available 至少为 102Gi,
直到不再有相关资源报告压力为止。
所有资源的默认 eviction-minimum-reclaim 值为 0。
调度器 当资源处于压力之下时,节点将报告状态。调度器将那种状态视为一种信号,阻止更多 pod 调度到这个节点上。
节点状态 调度器行为 MemoryPressure新的 BestEffort Pod 不会被调度到该节点 DiskPressure没有新的 Pod 会被调度到该节点
节点 OOM 行为 如果节点在 kubelet 回收内存之前经历了系统 OOM(内存不足)事件,它将基于
oom-killer 做出响应。
kubelet 基于 pod 的 service 质量为每个容器设置一个 oom_score_adj 值。
Service 质量 oom_score_adj Guaranteed-998 BestEffort1000 Burstablemin(max(2, 1000 - (1000 * memoryRequestBytes) / machineMemoryCapacityBytes), 999)
如果 kubelet 在节点经历系统 OOM 之前无法回收内存,oom_killer 将基于它在节点上
使用的内存百分比算出一个 oom_score,并加上 oom_score_adj 得到容器的有效
oom_score,然后结束得分最高的容器。
预期的行为应该是拥有最低服务质量并消耗和调度请求相关内存量最多的容器第一个被结束,以回收内存。
和 pod 驱逐不同,如果一个 Pod 的容器是被 OOM 结束的,基于其 RestartPolicy,
它可能会被 kubelet 重新启动。
最佳实践 以下部分描述了资源外处理的最佳实践。
可调度资源和驱逐策略 考虑以下场景:
节点内存容量:10Gi 操作员希望为系统守护进程保留 10% 内存容量(内核、kubelet等)。 操作员希望在内存用量达到 95% 时驱逐 pod,以减少对系统的冲击并防止系统 OOM 的发生。 为了促成这个场景,kubelet将像下面这样启动:
--eviction-hard=memory.available<500Mi
--system-reserved=memory=1.5Gi
这个配置的暗示是理解系统保留应该包含被驱逐阈值覆盖的内存数量。
要达到这个容量,要么某些 pod 使用了超过它们请求的资源,要么系统使用的内存超过 1.5Gi - 500Mi = 1Gi。
这个配置将保证在 pod 使用量都不超过它们配置的请求值时,如果可能立即引起内存压力并触发驱逐时,调度器不会将 pod 放到这个节点上。
DaemonSet 我们永远都不希望 kubelet 驱逐一个从 DaemonSet 派生的 Pod,因为这个 Pod 将立即被重建并调度回相同的节点。
目前,kubelet没有办法区分一个 Pod 是由 DaemonSet 还是其他对象创建。
如果/当这个信息可用时,kubelet 可能会预先将这些 pod 从提供给驱逐策略的候选集合中过滤掉。
总之,强烈推荐 DaemonSet 不要创建 BestEffort 的 Pod,防止其被识别为驱逐的候选 Pod。
相反,理想情况下 DaemonSet 应该启动 Guaranteed 的 pod。
现有的回收磁盘特性标签已被弃用 kubelet 已经按需求清空了磁盘空间以保证节点稳定性。
当磁盘驱逐成熟时,下面的 kubelet 标志将被标记为废弃的,以简化支持驱逐的配置。
现有标签 新标签 --image-gc-high-threshold--eviction-hard or eviction-soft--image-gc-low-threshold--eviction-minimum-reclaim--maximum-dead-containersdeprecated --maximum-dead-containers-per-containerdeprecated --minimum-container-ttl-durationdeprecated --low-diskspace-threshold-mb--eviction-hard or eviction-soft--outofdisk-transition-frequency--eviction-pressure-transition-period
已知问题 以下部分描述了与资源外处理有关的已知问题。
kubelet 可能无法立即发现内存压力 kubelet当前通过以固定的时间间隔轮询 cAdvisor 来收集内存使用数据。如果内存使用在那个时间窗口内迅速增长,kubelet可能不能足够快的发现 MemoryPressure,OOMKiller将不会被调用。我们准备在将来的发行版本中通过集成 memcg 通知 API 来减小这种延迟。当超过阈值时,内核将立即告诉我们。
如果您想处理可察觉的超量使用而不要求极端精准,可以设置驱逐阈值为大约 75% 容量作为这个问题的变通手段。这将增强这个特性的能力,防止系统 OOM,并提升负载卸载能力,以再次平衡集群状态。
kubelet 可能会驱逐超过需求数量的 pod 由于状态采集的时间差,驱逐操作可能驱逐比所需的更多的 pod。将来可通过添加从根容器获取所需状态的能力
https://github.com/google/cadvisor/issues/1247
来减缓这种状况。
4.2.40 - 限制存储消耗 此示例演示了一种限制名字空间中存储使用量的简便方法。
演示中用到了以下资源:ResourceQuota ,
LimitRange 和
PersistentVolumeClaim 。
准备开始 场景:限制存储消耗 集群管理员代表用户群操作集群,管理员希望控制单个名称空间可以消耗多少存储空间以控制成本。
管理员想要限制:
名字空间中持久卷申领(persistent volume claims)的数量 每个申领(claim)可以请求的存储量 名字空间可以具有的累计存储量 使用 LimitRange 限制存储请求 将 LimitRange 添加到名字空间会为存储请求大小强制设置最小值和最大值。
存储是通过 PersistentVolumeClaim 来发起请求的。
执行限制范围控制的准入控制器会拒绝任何高于或低于管理员所设阈值的 PVC。
在此示例中,请求 10Gi 存储的 PVC 将被拒绝,因为它超过了最大 2Gi。
apiVersion : v1
kind : LimitRange
metadata :
name : storagelimits
spec :
limits :
- type : PersistentVolumeClaim
max :
storage : 2Gi
min :
storage : 1Gi
当底层存储提供程序需要某些最小值时,将会用到所设置最小存储请求值。
例如,AWS EBS volumes 的最低要求为 1Gi。
使用 StorageQuota 限制 PVC 数目和累计存储容量 管理员可以限制某个名字空间中的 PVCs 个数以及这些 PVCs 的累计容量。
新 PVCs 请求如果超过任一上限值将被拒绝。
在此示例中,名字空间中的第 6 个 PVC 将被拒绝,因为它超过了最大计数 5。
或者,当与上面的 2Gi 最大容量限制结合在一起时,意味着 5Gi 的最大配额
不能支持 3 个都是 2Gi 的 PVC。
后者实际上是向名字空间请求 6Gi 容量,而该命令空间已经设置上限为 5Gi。
apiVersion : v1
kind : ResourceQuota
metadata :
name : storagequota
spec :
hard :
persistentvolumeclaims : "5"
requests.storage : "5Gi"
小结 限制范围对象可以用来设置可请求的存储量上限,而资源配额对象则可以通过申领计数和
累计存储容量有效地限制名字空间耗用的存储量。
这两种机制使得集群管理员能够规划其集群存储预算而不会发生任一项目超量分配的风险。
4.2.41 - 静态加密 Secret 数据 本文展示如何启用和配置静态 Secret 数据的加密
准备开始 配置并确定是否已启用静态数据加密 kube-apiserver 的参数 --experimental-encryption-provider-config 控制 API 数据在 etcd 中的加密方式。
下面提供一个配置示例。
理解静态数据加密 apiVersion : apiserver.config.k8s.io/v1
kind : EncryptionConfiguration
resources :
- resources :
- secrets
providers :
- identity : {}
- aesgcm :
keys :
- name : key1
secret : c2VjcmV0IGlzIHNlY3VyZQ==
- name : key2
secret : dGhpcyBpcyBwYXNzd29yZA==
- aescbc :
keys :
- name : key1
secret : c2VjcmV0IGlzIHNlY3VyZQ==
- name : key2
secret : dGhpcyBpcyBwYXNzd29yZA==
- secretbox :
keys :
- name : key1
secret : YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXoxMjM0NTY=
每个 resources 数组项目是一个单独的完整的配置。
resources.resources 字段是要加密的 Kubernetes 资源名称(resource 或 resource.group)的数组。
providers 数组是可能的加密 provider 的有序列表。
每个条目只能指定一个 provider 类型(可以是 identity 或 aescbc,但不能在同一个项目中同时指定)。
列表中的第一个 provider 用于加密进入存储的资源。
当从存储器读取资源时,与存储的数据匹配的所有 provider 将按顺序尝试解密数据。
如果由于格式或密钥不匹配而导致没有 provider 能够读取存储的数据,则会返回一个错误,以防止客户端访问该资源。
注意: 重要: 如果通过加密配置无法读取资源(因为密钥已更改),唯一的方法是直接从底层 etcd 中删除该密钥。
任何尝试读取资源的调用将会失败,直到它被删除或提供有效的解密密钥。
Providers: Kubernetes 静态数据加密的 Providers 名称 加密类型 强度 速度 密钥长度 其它事项 identity无 N/A N/A N/A 不加密写入的资源。当设置为第一个 provider 时,资源将在新值写入时被解密。 aescbc填充 PKCS#7 的 AES-CBC 最强 快 32字节 建议使用的加密项,但可能比 secretbox 稍微慢一些。 secretboxXSalsa20 和 Poly1305 强 更快 32字节 较新的标准,在需要高度评审的环境中可能不被接受。 aesgcm带有随机数的 AES-GCM 必须每 200k 写入一次 最快 16, 24 或者 32字节 建议不要使用,除非实施了自动密钥循环方案。 kms使用信封加密方案:数据使用带有 PKCS#7 填充的 AES-CBC 通过数据加密密钥(DEK)加密,DEK 根据 Key Management Service(KMS)中的配置通过密钥加密密钥(Key Encryption Keys,KEK)加密 最强 快 32字节 建议使用第三方工具进行密钥管理。为每个加密生成新的 DEK,并由用户控制 KEK 轮换来简化密钥轮换。配置 KMS 提供程序
每个 provider 都支持多个密钥 - 在解密时会按顺序使用密钥,如果是第一个 provider,则第一个密钥用于加密。
在 EncryptionConfig 中保存原始的加密密钥与不加密相比只会略微地提升安全级别。
请使用 kms 驱动以获得更强的安全性。
默认情况下,identity 驱动被用来对 etcd 中的 Secret 提供保护,
而这个驱动不提供加密能力。
EncryptionConfiguration 的引入是为了能够使用本地管理的密钥来在本地加密 Secret 数据。
使用本地管理的密钥来加密 Secret 能够保护数据免受 etcd 破坏的影响,不过无法针对
主机被侵入提供防护。
这是因为加密的密钥保存在主机上的 EncryptionConfig YAML 文件中,有经验的入侵者
仍能访问该文件并从中提取出加密密钥。
封套加密(Envelope Encryption)引入了对独立密钥的依赖,而这个密钥并不保存在 Kubernetes 中。
在这种情况下下,入侵者需要攻破 etcd、kube-apiserver 和第三方的 KMS
驱动才能获得明文数据,因而这种方案提供了比本地保存加密密钥更高的安全级别。
加密你的数据 创建一个新的加密配置文件:
apiVersion : apiserver.config.k8s.io/v1
kind : EncryptionConfiguration
resources :
- resources :
- secrets
providers :
- aescbc :
keys :
- name : key1
secret : <BASE 64 ENCODED SECRET>
- identity : {}
遵循如下步骤来创建一个新的 secret:
生成一个 32 字节的随机密钥并进行 base64 编码。如果你在 Linux 或 Mac OS X 上,请运行以下命令:
head -c 32 /dev/urandom | base64
将这个值放入到 secret 字段中。 设置 kube-apiserver 的 --experimental-encryption-provider-config 参数,将其指向
配置文件所在位置。 重启你的 API server。 注意: 你的配置文件包含可以解密 etcd 内容的密钥,因此你必须正确限制主控节点的访问权限,
以便只有能运行 kube-apiserver 的用户才能读取它。
验证数据已被加密 数据在写入 etcd 时会被加密。重新启动你的 kube-apiserver 后,任何新创建或更新的密码在存储时都应该被加密。
如果想要检查,你可以使用 etcdctl 命令行程序来检索你的加密内容。
创建一个新的 secret,名称为 secret1,命名空间为 default:
kubectl create secret generic secret1 -n default --from-literal= mykey = mydata
使用 etcdctl 命令行,从 etcd 中读取 secret:
ETCDCTL_API = 3 etcdctl get /registry/secrets/default/secret1 [ ...] | hexdump -C
这里的 [...] 是用来连接 etcd 服务的额外参数。
验证存储的密钥前缀是否为 k8s:enc:aescbc:v1:,这表明 aescbc provider 已加密结果数据。
通过 API 检索,验证 secret 是否被正确解密:
kubectl describe secret secret1 -n default
其输出应该是 mykey: bXlkYXRh,mydata 数据是被加密过的,请参阅
解密 Secret
了解如何完全解码 Secret 内容。
确保所有 Secret 都被加密 由于 Secret 是在写入时被加密,因此对 Secret 执行更新也会加密该内容。
kubectl get secrets --all-namespaces -o json | kubectl replace -f -
上面的命令读取所有 Secret,然后使用服务端加密来更新其内容。
说明: 如果由于冲突写入而发生错误,请重试该命令。
对于较大的集群,你可能希望通过命名空间或更新脚本来对 Secret 进行划分。
轮换解密密钥 在不发生停机的情况下更改 Secret 需要多步操作,特别是在有多个 kube-apiserver 进程正在运行的
高可用环境中。
生成一个新密钥并将其添加为所有服务器上当前提供程序的第二个密钥条目 重新启动所有 kube-apiserver 进程以确保每台服务器都可以使用新密钥进行解密 将新密钥设置为 keys 数组中的第一个条目,以便在配置中使用其进行加密 重新启动所有 kube-apiserver 进程以确保每个服务器现在都使用新密钥进行加密 运行 kubectl get secrets --all-namespaces -o json | kubectl replace -f - 以用新密钥加密所有现有的秘密 在使用新密钥备份 etcd 后,从配置中删除旧的解密密钥并更新所有密钥 如果只有一个 kube-apiserver,第 2 步可能可以忽略。
解密所有数据 要禁用 rest 加密,请将 identity provider 作为配置中的第一个条目:
apiVersion : apiserver.config.k8s.io/v1
kind : EncryptionConfiguration
resources :
- resources :
- secrets
providers :
- identity : {}
- aescbc :
keys :
- name : key1
secret : <BASE 64 ENCODED SECRET>
并重新启动所有 kube-apiserver 进程。然后运行:
kubectl get secrets -all-namespaces -o json | kubectl replace -f -`
以强制解密所有 secret。
4.3 - 配置 Pods 和容器 对 Pod 和容器执行常见的配置任务。
4.3.1 - 为容器和 Pod 分配内存资源 此页面展示如何将内存 请求 (request)和内存 限制 (limit)分配给一个容器。
我们保障容器拥有它请求数量的内存,但不允许使用超过限制数量的内存。
准备开始
你必须拥有一个 Kubernetes 的集群,同时你的 Kubernetes 集群必须带有 kubectl 命令行工具。
如果你还没有集群,你可以通过 Minikube 构建一
个你自己的集群,或者你可以使用下面任意一个 Kubernetes 工具构建:
要获知版本信息,请输入
kubectl version.
你集群中的每个节点必须拥有至少 300 MiB 的内存。
该页面上的一些步骤要求你在集群中运行
metrics-server 服务。
如果你已经有在运行中的 metrics-server,则可以跳过这些步骤。
如果你运行的是 Minikube,可以运行下面的命令启用 metrics-server:
minikube addons enable metrics-server
要查看 metrics-server 或资源指标 API (metrics.k8s.io) 是否已经运行,请运行以下命令:
如果资源指标 API 可用,则输出结果将包含对 metrics.k8s.io 的引用信息。
NAME
v1beta1.metrics.k8s.io
创建命名空间 创建一个命名空间,以便将本练习中创建的资源与集群的其余部分隔离。
kubectl create namespace mem-example
指定内存请求和限制 要为容器指定内存请求,请在容器资源清单中包含 resources:requests 字段。
同理,要指定内存限制,请包含 resources:limits。
在本练习中,你将创建一个拥有一个容器的 Pod。
容器将会请求 100 MiB 内存,并且内存会被限制在 200 MiB 以内。
这是 Pod 的配置文件:
apiVersion : v1
kind : Pod
metadata :
name : memory-demo
namespace : mem-example
spec :
containers :
- name : memory-demo-ctr
image : polinux/stress
resources :
limits :
memory : "200Mi"
requests :
memory : "100Mi"
command : ["stress" ]
args : ["--vm" , "1" , "--vm-bytes" , "150M" , "--vm-hang" , "1" ]
配置文件的 args 部分提供了容器启动时的参数。
"--vm-bytes", "150M" 参数告知容器尝试分配 150 MiB 内存。
开始创建 Pod:
kubectl apply -f https://k8s.io/examples/pods/resource/memory-request-limit.yaml --namespace= mem-example
验证 Pod 中的容器是否已运行:
kubectl get pod memory-demo --namespace= mem-example
查看 Pod 相关的详细信息:
kubectl get pod memory-demo --output= yaml --namespace= mem-example
输出结果显示:该 Pod 中容器的内存请求为 100 MiB,内存限制为 200 MiB。
...
resources :
limits :
memory : 200Mi
requests :
memory : 100Mi
...
运行 kubectl top 命令,获取该 Pod 的指标数据:
kubectl top pod memory-demo --namespace= mem-example
输出结果显示:Pod 正在使用的内存大约为 162,900,000 字节,约为 150 MiB。
这大于 Pod 请求的 100 MiB,但在 Pod 限制的 200 MiB之内。
NAME CPU(cores) MEMORY(bytes)
memory-demo <something> 162856960
删除 Pod:
kubectl delete pod memory-demo --namespace= mem-example
超过容器限制的内存 当节点拥有足够的可用内存时,容器可以使用其请求的内存。
但是,容器不允许使用超过其限制的内存。
如果容器分配的内存超过其限制,该容器会成为被终止的候选容器。
如果容器继续消耗超出其限制的内存,则终止容器。
如果终止的容器可以被重启,则 kubelet 会重新启动它,就像其他任何类型的运行时失败一样。
在本练习中,你将创建一个 Pod,尝试分配超出其限制的内存。
这是一个 Pod 的配置文件,其拥有一个容器,该容器的内存请求为 50 MiB,内存限制为 100 MiB:
apiVersion : v1
kind : Pod
metadata :
name : memory-demo-2
namespace : mem-example
spec :
containers :
- name : memory-demo-2-ctr
image : polinux/stress
resources :
requests :
memory : "50Mi"
limits :
memory : "100Mi"
command : ["stress" ]
args : ["--vm" , "1" , "--vm-bytes" , "250M" , "--vm-hang" , "1" ]
在配置文件的 args 部分中,你可以看到容器会尝试分配 250 MiB 内存,这远高于 100 MiB 的限制。
创建 Pod:
kubectl apply -f https://k8s.io/examples/pods/resource/memory-request-limit-2.yaml --namespace= mem-example
查看 Pod 相关的详细信息:
kubectl get pod memory-demo-2 --namespace= mem-example
此时,容器可能正在运行或被杀死。重复前面的命令,直到容器被杀掉:
NAME READY STATUS RESTARTS AGE
memory-demo-2 0/1 OOMKilled 1 24s
获取容器更详细的状态信息:
kubectl get pod memory-demo-2 --output= yaml --namespace= mem-example
输出结果显示:由于内存溢出(OOM),容器已被杀掉:
lastState:
terminated:
containerID: docker://65183c1877aaec2e8427bc95609cc52677a454b56fcb24340dbd22917c23b10f
exitCode: 137
finishedAt: 2017-06-20T20:52:19Z
reason: OOMKilled
startedAt: null
本练习中的容器可以被重启,所以 kubelet 会重启它。
多次运行下面的命令,可以看到容器在反复的被杀死和重启:
kubectl get pod memory-demo-2 --namespace= mem-example
输出结果显示:容器被杀掉、重启、再杀掉、再重启……:
kubectl get pod memory-demo-2 --namespace=mem-example
NAME READY STATUS RESTARTS AGE
memory-demo-2 0/1 OOMKilled 1 37s
kubectl get pod memory-demo-2 --namespace=mem-example
NAME READY STATUS RESTARTS AGE
memory-demo-2 1/1 Running 2 40s
查看关于该 Pod 历史的详细信息:
kubectl describe pod memory-demo-2 --namespace=mem-example
输出结果显示:该容器反复的在启动和失败:
... Normal Created Created container with id 66a3a20aa7980e61be4922780bf9d24d1a1d8b7395c09861225b0eba1b1f8511
... Warning BackOff Back-off restarting failed container
查看关于集群节点的详细信息:
kubectl describe nodes
输出结果包含了一条练习中的容器由于内存溢出而被杀掉的记录:
Warning OOMKilling Memory cgroup out of memory: Kill process 4481 (stress) score 1994 or sacrifice child
删除 Pod:
kubectl delete pod memory-demo-2 --namespace= mem-example
超过整个节点容量的内存 内存请求和限制是与容器关联的,但将 Pod 视为具有内存请求和限制,也是很有用的。
Pod 的内存请求是 Pod 中所有容器的内存请求之和。
同理,Pod 的内存限制是 Pod 中所有容器的内存限制之和。
Pod 的调度基于请求。只有当节点拥有足够满足 Pod 内存请求的内存时,才会将 Pod 调度至节点上运行。
在本练习中,你将创建一个 Pod,其内存请求超过了你集群中的任意一个节点所拥有的内存。
这是该 Pod 的配置文件,其拥有一个请求 1000 GiB 内存的容器,这应该超过了你集群中任何节点的容量。
apiVersion : v1
kind : Pod
metadata :
name : memory-demo-3
namespace : mem-example
spec :
containers :
- name : memory-demo-3-ctr
image : polinux/stress
resources :
limits :
memory : "1000Gi"
requests :
memory : "1000Gi"
command : ["stress" ]
args : ["--vm" , "1" , "--vm-bytes" , "150M" , "--vm-hang" , "1" ]
创建 Pod:
kubectl apply -f https://k8s.io/examples/pods/resource/memory-request-limit-3.yaml --namespace= mem-example
查看 Pod 状态:
kubectl get pod memory-demo-3 --namespace= mem-example
输出结果显示:Pod 处于 PENDING 状态。
这意味着,该 Pod 没有被调度至任何节点上运行,并且它会无限期的保持该状态:
kubectl get pod memory-demo-3 --namespace=mem-example
NAME READY STATUS RESTARTS AGE
memory-demo-3 0/1 Pending 0 25s
查看关于 Pod 的详细信息,包括事件:
kubectl describe pod memory-demo-3 --namespace= mem-example
输出结果显示:由于节点内存不足,该容器无法被调度:
Events:
... Reason Message
------ -------
... FailedScheduling No nodes are available that match all of the following predicates:: Insufficient memory ( 3) .
内存单位 内存资源的基本单位是字节(byte)。你可以使用这些后缀之一,将内存表示为
纯整数或定点整数:E、P、T、G、M、K、Ei、Pi、Ti、Gi、Mi、Ki。
例如,下面是一些近似相同的值:
128974848, 129e6, 129M , 123Mi
删除 Pod:
kubectl delete pod memory-demo-3 --namespace= mem-example
如果你没有指定内存限制 如果你没有为一个容器指定内存限制,则自动遵循以下情况之一:
内存请求和限制的目的 通过为集群中运行的容器配置内存请求和限制,你可以有效利用集群节点上可用的内存资源。
通过将 Pod 的内存请求保持在较低水平,你可以更好地安排 Pod 调度。
通过让内存限制大于内存请求,你可以完成两件事:
Pod 可以进行一些突发活动,从而更好的利用可用内存。 Pod 在突发活动期间,可使用的内存被限制为合理的数量。 清理 删除命名空间。下面的命令会删除你根据这个任务创建的所有 Pod:
kubectl delete namespace mem-example
接下来 应用开发者扩展阅读 集群管理员扩展阅读 4.3.2 - 为 Windows Pod 和容器配置 GMSA FEATURE STATE: Kubernetes v1.18 [stable]
本页展示如何为将运行在 Windows 节点上的 Pod 和容器配置
组管理的服务账号(Group Managed Service Accounts,GMSA) 。
组管理的服务账号是活动目录(Active Directory)的一种特殊类型,提供自动化的
密码管理、简化的服务主体名称(Service Principal Name,SPN)管理以及跨多个
服务器将管理操作委派给其他管理员等能力。
在 Kubernetes 环境中,GMSA 凭据规约配置为 Kubernetes 集群范围的自定义资源
(Custom Resources)形式。Windows Pod 以及各 Pod 中的每个容器可以配置为
使用 GMSA 来完成基于域(Domain)的操作(例如,Kerberos 身份认证),以便
与其他 Windows 服务相交互。自 Kubernetes 1.16 版本起,Docker 运行时为
Windows 负载支持 GMSA。
准备开始 你需要一个 Kubernetes 集群,以及 kubectl 命令行工具,且工具必须已配置
为能够与你的集群通信。集群预期包含 Windows 工作节点。
本节讨论需要为每个集群执行一次的初始操作。
安装 GMSACredentialSpec CRD 你需要在集群上配置一个用于 GMSA 凭据规约资源的
CustomResourceDefinition (CRD),
以便定义类型为 GMSACredentialSpec 的自定义资源。
首先下载 GMSA CRD YAML
并将其保存为 gmsa-crd.yaml。接下来执行 kubectl apply -f gmsa-crd.yaml
安装 CRD。
安装 Webhook 来验证 GMSA 用户 你需要为 Kubernetes 集群配置两个 Webhook,在 Pod 或容器级别填充和检查
GMSA 凭据规约引用。
一个修改模式(Mutating)的 Webhook,将对 GMSA 的引用(在 Pod 规约中体现为名字)
展开为完整凭据规约的 JSON 形式,并保存回 Pod 规约中。
一个验证模式(Validating)的 Webhook,确保对 GMSA 的所有引用都是已经授权
给 Pod 的服务账号使用的。
安装以上 Webhook 及其相关联的对象需要执行以下步骤:
创建一个证书密钥对(用于允许 Webhook 容器与集群通信)
安装一个包含如上证书的 Secret
创建一个包含核心 Webhook 逻辑的 Deployment
创建引用该 Deployment 的 Validating Webhook 和 Mutating Webhook 配置
你可以使用这个脚本
来部署和配置上述 GMSA Webhook 及相关联的对象。你还可以在运行脚本时设置 --dry-run=server
选项以便审查脚本将会对集群做出的变更。
脚本所使用的YAML 模板
也可用于手动部署 Webhook 及相关联的对象,不过需要对其中的参数作适当替换。
在活动目录中配置 GMSA 和 Windows 节点 在配置 Kubernetes 中的 Pod 以使用 GMSA 之前,需要按
Windows GMSA 文档
中描述的那样先在活动目录中准备好期望的 GMSA。
Windows 工作节点(作为 Kubernetes 集群的一部分)需要被配置到活动目录中,以便
访问与期望的 GSMA 相关联的秘密凭据数据。这一操作的描述位于
Windows GMSA 文档
中。
创建 GMSA 凭据规约资源 当(如前所述)安装了 GMSACredentialSpec CRD 之后,你就可以配置包含 GMSA 凭据
规约的自定义资源了。GMSA 凭据规约中并不包含秘密或敏感数据。
其中包含的信息主要用于容器运行时,便于后者向 Windows 描述容器所期望的 GMSA。
GMSA 凭据规约可以使用
PowerShell 脚本
以 YAML 格式生成。
下面是手动以 JSON 格式生成 GMSA 凭据规约并对其进行 YAML 转换的步骤:
导入 CredentialSpec 模块 : ipmo CredentialSpec.psm1
使用 New-CredentialSpec 来创建一个 JSON 格式的凭据规约。
要创建名为 WebApp1 的 GMSA 凭据规约,调用
New-CredentialSpec -Name WebApp1 -AccountName WebApp1 -Domain $(Get-ADDomain -Current LocalComputer)。
使用 Get-CredentialSpec 来显示 JSON 文件的路径。
将凭据规约从 JSON 格式转换为 YAML 格式,并添加必要的头部字段
apiVersion、kind、metadata 和 credspec,使其成为一个可以在
Kubernetes 中配置的 GMSACredentialSpec 自定义资源。
下面的 YAML 配置描述的是一个名为 gmsa-WebApp1 的 GMSA 凭据规约:
apiVersion : windows.k8s.io/v1alpha1
kind : GMSACredentialSpec
metadata :
name : gmsa-WebApp1 # 这是随意起的一个名字,将用作引用
credspec :
ActiveDirectoryConfig :
GroupManagedServiceAccounts :
- Name : WebApp1 # GMSA 账号的用户名
Scope : CONTOSO # NETBIOS 域名
- Name : WebApp1 # GMSA 账号的用户名
Scope : contoso.com # DNS 域名
CmsPlugins :
- ActiveDirectory
DomainJoinConfig :
DnsName : contoso.com # DNS 域名
DnsTreeName : contoso.com # DNS 域名根
Guid : 244818ae-87ac-4fcd-92ec-e79e5252348a # GUID
MachineAccountName : WebApp1 # GMSA 账号的用户名
NetBiosName : CONTOSO # NETBIOS 域名
Sid : S-1-5-21-2126449477-2524075714-3094792973 # GMSA 的 SID
上面的凭据规约资源可以保存为 gmsa-Webapp1-credspec.yaml,之后使用
kubectl apply -f gmsa-Webapp1-credspec.yml 应用到集群上。
配置集群角色以启用对特定 GMSA 凭据规约的 RBAC 你需要为每个 GMSA 凭据规约资源定义集群角色。
该集群角色授权某主体(通常是一个服务账号)对特定的 GMSA 资源执行 use 动作。
下面的示例显示的是一个集群角色,对前文创建的凭据规约 gmsa-WebApp1 执行鉴权。
将此文件保存为 gmsa-webapp1-role.yaml 并执行 kubectl apply -f gmsa-webapp1-role.yaml。
# 创建集群角色读取凭据规约
apiVersion : rbac.authorization.k8s.io/v1
kind : ClusterRole
metadata :
name : webapp1-role
rules :
- apiGroups : ["windows.k8s.io" ]
resources : ["gmsacredentialspecs" ]
verbs : ["use" ]
resourceNames : ["gmsa-WebApp1" ]
将角色指派给要使用特定 GMSA 凭据规约的服务账号 你需要将某个服务账号(Pod 配置所对应的那个)绑定到前文创建的集群角色上。
这一绑定操作实际上授予该服务账号使用所指定的 GMSA 凭据规约资源的访问权限。
下面显示的是一个绑定到集群角色 webapp1-role 上的 default 服务账号,使之
能够使用前面所创建的 gmsa-WebApp1 凭据规约资源。
apiVersion : rbac.authorization.k8s.io/v1
kind : RoleBinding
metadata :
name : allow-default-svc-account-read-on-gmsa-WebApp1
namespace : default
subjects :
- kind : ServiceAccount
name : default
namespace : default
roleRef :
kind : ClusterRole
name : webapp1-role
apiGroup : rbac.authorization.k8s.io
在 Pod 规约中配置 GMSA 凭据规约引用 Pod 规约字段 securityContext.windowsOptions.gmsaCredentialSpecName 可用来
设置对指定 GMSA 凭据规约自定义资源的引用。
设置此引用将会配置 Pod 中的所有容器使用所给的 GMSA。
下面是一个 Pod 规约示例,其中包含了对 gmsa-WebApp1 凭据规约的引用:
apiVersion : apps/v1
kind : Deployment
metadata :
labels :
run : with-creds
name : with-creds
namespace : default
spec :
replicas : 1
selector :
matchLabels :
run : with-creds
template :
metadata :
labels :
run : with-creds
spec :
securityContext :
windowsOptions :
gmsaCredentialSpecName : gmsa-webapp1
containers :
- image : mcr.microsoft.com/windows/servercore/iis:windowsservercore-ltsc2019
imagePullPolicy : Always
name : iis
nodeSelector :
kubernetes.io/os : windows
Pod 中的各个容器也可以使用对应容器的 securityContext.windowsOptions.gmsaCredentialSpecName
字段来设置期望使用的 GMSA 凭据规约。
例如:
apiVersion : apps/v1
kind : Deployment
metadata :
labels :
run : with-creds
name : with-creds
namespace : default
spec :
replicas : 1
selector :
matchLabels :
run : with-creds
template :
metadata :
labels :
run : with-creds
spec :
containers :
- image : mcr.microsoft.com/windows/servercore/iis:windowsservercore-ltsc2019
imagePullPolicy : Always
name : iis
securityContext :
windowsOptions :
gmsaCredentialSpecName : gmsa-Webapp1
nodeSelector :
kubernetes.io/os : windows
当 Pod 规约中填充了 GMSA 相关字段(如上所述),在集群中应用 Pod 规约时会依次
发生以下事件:
Mutating Webhook 解析对 GMSA 凭据规约资源的引用,并将其全部展开,
得到 GMSA 凭据规约的实际内容。
Validating Webhook 确保与 Pod 相关联的服务账号有权在所给的 GMSA 凭据规约
上执行 use 动作。
容器运行时为每个 Windows 容器配置所指定的 GMSA 凭据规约,这样容器就可以以
活动目录中该 GMSA 所代表的身份来执行操作,使用该身份来访问域中的服务。
故障排查 如果在你的环境中配置 GMSA 时遇到了困难,你可以采取若干步骤来排查可能
的故障。
首先,确保凭据规约已经被传递到 Pod。要实现这点,你需要先通过 exec 进入到
你的 Pod 之一,检查 nltest.exe /parentdomain 命令的输出。
在下面的例子中,Pod 未能正确地获得凭据规约:
kubectl exec -it iis-auth-7776966999-n5nzr powershell.exe
Windows PowerShell
Copyright ( C) Microsoft Corporation. All rights reserved.
PS C:\> nltest.exe /parentdomain
Getting parent domain failed: Status = 1722 0x6ba RPC_S_SERVER_UNAVAILABLE
PS C:\>
如果 Pod 未能正确获得凭据规约,则下一步就要检查与域之间的通信。
首先,从 Pod 内部快速执行一个 nslookup 操作,找到域根。
这一操作会告诉我们三件事情:
Pod 能否访问域控制器(DC) DC 能否访问 Pod DNS 是否正常工作 如果 DNS 和通信测试通过,接下来你需要检查是否 Pod 已经与域之间建立了
安全通信通道。要执行这一检查,你需要再次通过 exec 进入到你的 Pod 中
并执行 nltest.exe /query 命令。
PS C:\> nltest.exe /query
I_NetLogonControl failed: Status = 1722 0x6ba RPC_S_SERVER_UNAVAILABLE
这一输出告诉我们,由于某些原因,Pod 无法使用凭据规约中的账号登录到域。
你可以通过运行 nltest.exe /sc_reset:domain.example 命令尝试修复安全通道。
PS C:\> nltest /sc_reset:domain.example
Flags: 30 HAS_IP HAS_TIMESERV
Trusted DC Name \\ dc10.domain.example
Trusted DC Connection Status Status = 0 0x0 NERR_Success
The command completed successfully
PS C:\>
如果上述命令修复了错误,你就可以通过向你的 Pod 规约添加生命周期回调来将此操作
自动化。如果上述命令未能奏效,你就需要再次检查凭据规约,以确保其数据时正确的
而且是完整的。
image : registry.domain.example/iis-auth:1809v1
lifecycle :
postStart :
exec :
command : ["powershell.exe" ,"-command" ,"do { Restart-Service -Name netlogon } while ( $($Result = (nltest.exe /query); if ($Result -like '*0x0 NERR_Success*') {return $true} else {return $false}) -eq $false)" ]
imagePullPolicy : IfNotPresent
如果你向你的 Pod 规约中添加如上所示的 lifecycle 节,则 Pod 会自动执行所
列举的命令来重启 netlogon 服务,直到 nltest.exe /query
命令返回时没有错误信息。
GMSA 的局限 在使用 Windows 版本的 ContainerD 运行时
时,通过 GMSA 域身份标识访问受限制的网络共享资源时会出错。
容器会收到身份标识且 nltest.exe /query 调用也能正常工作。
当需要访问网络共享资源时,建议使用
Docker EE 运行时 。
Windows Server 团队正在 Windows 内核中解决这一问题,并在将来发布解决此问题的补丁。
你可以在 Microsoft Windows Containers 问题跟踪列表
中查找这类更新。
4.3.3 - 为 Windows 的 Pod 和容器配置 RunAsUserName FEATURE STATE: Kubernetes v1.18 [stable]
本页展示如何为运行为在 Windows 节点上运行的 Pod 和容器配置 RunAsUserName 。
大致相当于 Linux 上的 runAsUser,允许在容器中以与默认值不同的用户名运行应用。
准备开始 你必须有一个 Kubernetes 集群,并且 kubectl 必须能和集群通信。
集群应该要有 Windows 工作节点,将在其中调度运行 Windows 工作负载的 pod 和容器。
为 Pod 设置 Username 要指定运行 Pod 容器时所使用的用户名,请在 Pod 声明中包含 securityContext
(PodSecurityContext )字段,
并在其内部包含 windowsOptions
(WindowsSecurityContextOptions )
字段的 runAsUserName 字段。
你为 Pod 指定的 Windows SecurityContext 选项适用于该 Pod 中(包括 init 容器)的所有容器。
这儿有一个已经设置了 runAsUserName 字段的 Windows Pod 的配置文件:
apiVersion : v1
kind : Pod
metadata :
name : run-as-username-pod-demo
spec :
securityContext :
windowsOptions :
runAsUserName : "ContainerUser"
containers :
- name : run-as-username-demo
image : mcr.microsoft.com/windows/servercore:ltsc2019
command : ["ping" , "-t" , "localhost" ]
nodeSelector :
kubernetes.io/os : windows
创建 Pod:
kubectl apply -f https://k8s.io/examples/windows/run-as-username-pod.yaml
验证 Pod 容器是否在运行:
kubectl get pod run-as-username-pod-demo
获取该容器的 shell:
kubectl exec -it run-as-username-pod-demo -- powershell
检查运行 shell 的用户的用户名是否正确:
输出结果应该是这样:
为容器设置 Username 要指定运行容器时所使用的用户名,请在容器清单中包含 securityContext
(SecurityContext )
字段,并在其内部包含 windowsOptions
(WindowsSecurityContextOptions )
字段的 runAsUserName 字段。
你为容器指定的 Windows SecurityContext 选项仅适用于该容器,并且它会覆盖 Pod 级别设置。
这里有一个 Pod 的配置文件,其中只有一个容器,并且在 Pod 级别和容器级别都设置了 runAsUserName:
apiVersion : v1
kind : Pod
metadata :
name : run-as-username-container-demo
spec :
securityContext :
windowsOptions :
runAsUserName : "ContainerUser"
containers :
- name : run-as-username-demo
image : mcr.microsoft.com/windows/servercore:ltsc2019
command : ["ping" , "-t" , "localhost" ]
securityContext :
windowsOptions :
runAsUserName : "ContainerAdministrator"
nodeSelector :
kubernetes.io/os : windows
创建 Pod:
kubectl apply -f https://k8s.io/examples/windows/run-as-username-container.yaml
验证 Pod 容器是否在运行:
kubectl get pod run-as-username-container-demo
获取该容器的 shell:
kubectl exec -it run-as-username-container-demo -- powershell
检查运行 shell 的用户的用户名是否正确(应该是容器级别设置的那个):
输出结果应该是这样:
ContainerAdministrator
Windows Username 的局限性 想要使用此功能,在 runAsUserName 字段中设置的值必须是有效的用户名。
它必须是 DOMAIN\USER 这种格式,其中 DOMAIN\ 是可选的。
Windows 用户名不区分大小写。此外,关于 DOMAIN 和 USER 还有一些限制:
runAsUserName 字段不能为空,并且不能包含控制字符(ASCII 值:0x00-0x1F、0x7F)DOMAIN 必须是 NetBios 名称或 DNS 名称,每种名称都有各自的局限性:NetBios 名称:最多 15 个字符,不能以 .(点)开头,并且不能包含以下字符:\ / : * ? " < > | DNS 名称:最多 255 个字符,只能包含字母、数字、点和中划线,并且不能以 .(点)或 -(中划线)开头和结尾。 USER 最多不超过 20 个字符,不能 只 包含点或空格,并且不能包含以下字符:" / \ [ ] : ; | = , + * ? < > @runAsUserName 字段接受的值的一些示例:ContainerAdministrator、ContainerUser、
NT AUTHORITY\NETWORK SERVICE、NT AUTHORITY\LOCAL SERVICE。
关于这些限制的更多信息,可以查看这里 和这里 。
接下来 4.3.4 - 为容器和 Pods 分配 CPU 资源 本页面展示如何为容器设置 CPU request(请求) 和 CPU limit(限制) 。
容器使用的 CPU 不能超过所配置的限制。
如果系统有空闲的 CPU 时间,则可以保证给容器分配其所请求数量的 CPU 资源。
准备开始
你必须拥有一个 Kubernetes 的集群,同时你的 Kubernetes 集群必须带有 kubectl 命令行工具。
如果你还没有集群,你可以通过 Minikube 构建一
个你自己的集群,或者你可以使用下面任意一个 Kubernetes 工具构建:
要获知版本信息,请输入
kubectl version.
集群中的每个节点必须至少有 1 个 CPU 可用才能运行本任务中的示例。
本页的一些步骤要求你在集群中运行
metrics-server
服务。如果你的集群中已经有正在运行的 metrics-server 服务,可以跳过这些步骤。
如果你正在运行Minikube ,请运行以下命令启用 metrics-server:
minikube addons enable metrics-server
查看 metrics-server(或者其他资源度量 API metrics.k8s.io 服务提供者)是否正在运行,
请键入以下命令:
如果资源指标 API 可用,则会输出将包含一个对 metrics.k8s.io 的引用。
NAME
v1beta1.metrics.k8s.io
创建一个名字空间 创建一个名字空间 ,以便将
本练习中创建的资源与集群的其余部分资源隔离。
kubectl create namespace cpu-example
指定 CPU 请求和 CPU 限制 要为容器指定 CPU 请求,请在容器资源清单中包含 resources: requests 字段。
要指定 CPU 限制,请包含 resources:limits。
在本练习中,你将创建一个具有一个容器的 Pod。容器将会请求 0.5 个 CPU,而且最多限制使用 1 个 CPU。
这是 Pod 的配置文件:
apiVersion : v1
kind : Pod
metadata :
name : cpu-demo
namespace : cpu-example
spec :
containers :
- name : cpu-demo-ctr
image : vish/stress
resources :
limits :
cpu : "1"
requests :
cpu : "0.5"
args :
- -cpus
- "2"
配置文件的 args 部分提供了容器启动时的参数。
-cpus "2" 参数告诉容器尝试使用 2 个 CPU。
创建 Pod:
kubectl apply -f https://k8s.io/examples/pods/resource/cpu-request-limit.yaml --namespace= cpu-example
验证所创建的 Pod 处于 Running 状态
kubectl get pod cpu-demo --namespace= cpu-example
查看显示关于 Pod 的详细信息:
kubectl get pod cpu-demo --output= yaml --namespace= cpu-example
输出显示 Pod 中的一个容器的 CPU 请求为 500 milli CPU,并且 CPU 限制为 1 个 CPU。
resources :
limits :
cpu : "1"
requests :
cpu : 500m
使用 kubectl top 命令来获取该 Pod 的度量值数据:
kubectl top pod cpu-demo --namespace= cpu-example
此示例输出显示 Pod 使用的是 974 milliCPU,即仅略低于 Pod 配置中指定的 1 个 CPU 的限制。
NAME CPU(cores) MEMORY(bytes)
cpu-demo 974m <something>
回想一下,通过设置 -cpu "2",你将容器配置为尝试使用 2 个 CPU,
但是容器只被允许使用大约 1 个 CPU。
容器的 CPU 用量受到限制,因为该容器正尝试使用超出其限制的 CPU 资源。
说明: CPU 使用率低于 1.0 的另一种可能的解释是,节点可能没有足够的 CPU 资源可用。
回想一下,此练习的先决条件需要你的节点至少具有 1 个 CPU 可用。
如果你的容器在只有 1 个 CPU 的节点上运行,则容器无论为容器指定的 CPU 限制如何,
都不能使用超过 1 个 CPU。
CPU 单位 CPU 资源以 CPU 单位度量。Kubernetes 中的一个 CPU 等同于:
1 个 AWS vCPU 1 个 GCP核心 1 个 Azure vCore 裸机上具有超线程能力的英特尔处理器上的 1 个超线程 小数值是可以使用的。一个请求 0.5 CPU 的容器保证会获得请求 1 个 CPU 的容器的 CPU 的一半。
你可以使用后缀 m 表示毫。例如 100m CPU、100 milliCPU 和 0.1 CPU 都相同。
精度不能超过 1m。
CPU 请求只能使用绝对数量,而不是相对数量。0.1 在单核、双核或 48 核计算机上的 CPU 数量值是一样的。
删除 Pod:
kubectl delete pod cpu-demo --namespace= cpu-example
设置超过节点能力的 CPU 请求 CPU 请求和限制与都与容器相关,但是我们可以考虑一下 Pod 具有对应的 CPU 请求和限制这样的场景。
Pod 对 CPU 用量的请求等于 Pod 中所有容器的请求数量之和。
同样,Pod 的 CPU 资源限制等于 Pod 中所有容器 CPU 资源限制数之和。
Pod 调度是基于资源请求值来进行的。
仅在某节点具有足够的 CPU 资源来满足 Pod CPU 请求时,Pod 将会在对应节点上运行:
在本练习中,你将创建一个 Pod,该 Pod 的 CPU 请求对于集群中任何节点的容量而言都会过大。
下面是 Pod 的配置文件,其中有一个容器。容器请求 100 个 CPU,这可能会超出集群中任何节点的容量。
apiVersion : v1
kind : Pod
metadata :
name : cpu-demo-2
namespace : cpu-example
spec :
containers :
- name : cpu-demo-ctr-2
image : vish/stress
resources :
limits :
cpu : "100"
requests :
cpu : "100"
args :
- -cpus
- "2"
创建 Pod:
kubectl apply -f https://k8s.io/examples/pods/resource/cpu-request-limit-2.yaml --namespace= cpu-example
查看该 Pod 的状态:
kubectl get pod cpu-demo-2 --namespace= cpu-example
输出显示 Pod 状态为 Pending。也就是说,Pod 未被调度到任何节点上运行,
并且 Pod 将无限期地处于 Pending 状态:
NAME READY STATUS RESTARTS AGE
cpu-demo-2 0/1 Pending 0 7m
查看有关 Pod 的详细信息,包含事件:
kubectl describe pod cpu-demo-2 --namespace= cpu-example
输出显示由于节点上的 CPU 资源不足,无法调度容器:
Events:
Reason Message
------ -------
FailedScheduling No nodes are available that match all of the following predicates:: Insufficient cpu (3).
删除你的 Pod:
kubectl delete pod cpu-demo-2 --namespace= cpu-example
如果不指定 CPU 限制 如果你没有为容器指定 CPU 限制,则会发生以下情况之一:
如果你设置了 CPU 限制但未设置 CPU 请求 如果你为容器指定了 CPU 限制值但未为其设置 CPU 请求,Kubernetes 会自动为其
设置与 CPU 限制相同的 CPU 请求值。类似的,如果容器设置了内存限制值但未设置
内存请求值,Kubernetes 也会为其设置与内存限制值相同的内存请求。
CPU 请求和限制的初衷 通过配置你的集群中运行的容器的 CPU 请求和限制,你可以有效利用集群上可用的 CPU 资源。
通过将 Pod CPU 请求保持在较低水平,可以使 Pod 更有机会被调度。
通过使 CPU 限制大于 CPU 请求,你可以完成两件事:
Pod 可能会有突发性的活动,它可以利用碰巧可用的 CPU 资源。 Pod 在突发负载期间可以使用的 CPU 资源数量仍被限制为合理的数量。 清理 删除名称空间:
kubectl delete namespace cpu-example
接下来 针对应用开发者 针对集群管理员 4.3.5 - 配置 Pod 的服务质量 本页介绍怎样配置 Pod 让其获得特定的服务质量(QoS)类。Kubernetes 使用 QoS 类来决定 Pod 的调度和驱逐策略。
准备开始
你必须拥有一个 Kubernetes 的集群,同时你的 Kubernetes 集群必须带有 kubectl 命令行工具。
如果你还没有集群,你可以通过 Minikube 构建一
个你自己的集群,或者你可以使用下面任意一个 Kubernetes 工具构建:
要获知版本信息,请输入
kubectl version.
QoS 类 Kubernetes 创建 Pod 时就给它指定了下列一种 QoS 类:
Guaranteed Burstable BestEffort 创建命名空间 创建一个命名空间,以便将本练习所创建的资源与集群的其余资源相隔离。
kubectl create namespace qos-example
创建一个 QoS 类为 Guaranteed 的 Pod 对于 QoS 类为 Guaranteed 的 Pod:
Pod 中的每个容器,包含初始化容器,必须指定内存请求和内存限制,并且两者要相等。 Pod 中的每个容器,包含初始化容器,必须指定 CPU 请求和 CPU 限制,并且两者要相等。 下面是包含一个容器的 Pod 配置文件。
容器设置了内存请求和内存限制,值都是 200 MiB。
容器设置了 CPU 请求和 CPU 限制,值都是 700 milliCPU:
apiVersion : v1
kind : Pod
metadata :
name : qos-demo
namespace : qos-example
spec :
containers :
- name : qos-demo-ctr
image : nginx
resources :
limits :
memory : "200Mi"
cpu : "700m"
requests :
memory : "200Mi"
cpu : "700m"
创建 Pod:
kubectl create -f https://k8s.io/examples/pods/qos/qos-pod.yaml --namespace= qos-example
查看 Pod 详情:
kubectl get pod qos-demo --namespace= qos-example --output= yaml
结果表明 Kubernetes 为 Pod 配置的 QoS 类为 Guaranteed。
结果也确认了 Pod 容器设置了与内存限制匹配的内存请求,设置了与 CPU 限制匹配的 CPU 请求。
spec :
containers :
...
resources :
limits :
cpu : 700m
memory : 200Mi
requests :
cpu : 700m
memory : 200Mi
...
status :
qosClass : Guaranteed
说明: 如果容器指定了自己的内存限制,但没有指定内存请求,Kubernetes 会自动为它指定与内存限制匹配的内存请求。
同样,如果容器指定了自己的 CPU 限制,但没有指定 CPU 请求,Kubernetes 会自动为它指定与 CPU 限制匹配的 CPU 请求。
删除 Pod:
kubectl delete pod qos-demo --namespace= qos-example
创建一个 QoS 类为 Burstable 的 Pod 如果满足下面条件,将会指定 Pod 的 QoS 类为 Burstable:
Pod 不符合 Guaranteed QoS 类的标准。 Pod 中至少一个容器具有内存或 CPU 请求。 下面是包含一个容器的 Pod 配置文件。
容器设置了内存限制 200 MiB 和内存请求 100 MiB。
apiVersion : v1
kind : Pod
metadata :
name : qos-demo-2
namespace : qos-example
spec :
containers :
- name : qos-demo-2-ctr
image : nginx
resources :
limits :
memory : "200Mi"
requests :
memory : "100Mi"
创建 Pod:
kubectl create -f https://k8s.io/examples/pods/qos/qos-pod-2.yaml --namespace= qos-example
查看 Pod 详情:
kubectl get pod qos-demo-2 --namespace= qos-example --output= yaml
结果表明 Kubernetes 为 Pod 配置的 QoS 类为 Burstable。
spec :
containers :
- image : nginx
imagePullPolicy : Always
name : qos-demo-2-ctr
resources :
limits :
memory : 200Mi
requests :
memory : 100Mi
...
status :
qosClass : Burstable
删除 Pod:
kubectl delete pod qos-demo-2 --namespace= qos-example
创建一个 QoS 类为 BestEffort 的 Pod 对于 QoS 类为 BestEffort 的 Pod,Pod 中的容器必须没有设置内存和 CPU 限制或请求。
下面是包含一个容器的 Pod 配置文件。
容器没有设置内存和 CPU 限制或请求。
apiVersion : v1
kind : Pod
metadata :
name : qos-demo-3
namespace : qos-example
spec :
containers :
- name : qos-demo-3-ctr
image : nginx
创建 Pod:
kubectl create -f https://k8s.io/examples/pods/qos/qos-pod-3.yaml --namespace= qos-example
查看 Pod 详情:
kubectl get pod qos-demo-3 --namespace= qos-example --output= yaml
结果表明 Kubernetes 为 Pod 配置的 QoS 类为 BestEffort。
spec :
containers :
...
resources : {}
...
status :
qosClass : BestEffort
删除 Pod:
kubectl delete pod qos-demo-3 --namespace= qos-example
创建包含两个容器的 Pod 下面是包含两个容器的 Pod 配置文件。
一个容器指定了内存请求 200 MiB。
另外一个容器没有指定任何请求和限制。
apiVersion : v1
kind : Pod
metadata :
name : qos-demo-4
namespace : qos-example
spec :
containers :
- name : qos-demo-4-ctr-1
image : nginx
resources :
requests :
memory : "200Mi"
- name : qos-demo-4-ctr-2
image : redis
注意此 Pod 满足 Burstable QoS 类的标准。
也就是说它不满足 Guaranteed QoS 类标准,因为它的一个容器设有内存请求。
创建 Pod:
kubectl create -f https://k8s.io/examples/pods/qos/qos-pod-4.yaml --namespace= qos-example
查看 Pod 详情:
kubectl get pod qos-demo-4 --namespace= qos-example --output= yaml
结果表明 Kubernetes 为 Pod 配置的 QoS 类为 Burstable:
spec :
containers :
...
name : qos-demo-4-ctr-1
resources :
requests :
memory : 200Mi
...
name : qos-demo-4-ctr-2
resources : {}
...
status :
qosClass : Burstable
删除 Pod:
kubectl delete pod qos-demo-4 --namespace= qos-example
环境清理 删除命名空间:
kubectl delete namespace qos-example
接下来 应用开发者参考 集群管理员参考 4.3.6 - 为容器分派扩展资源 FEATURE STATE: Kubernetes v1.20 [stable]
本文介绍如何为容器指定扩展资源。
准备开始
你必须拥有一个 Kubernetes 的集群,同时你的 Kubernetes 集群必须带有 kubectl 命令行工具。
如果你还没有集群,你可以通过 Minikube 构建一
个你自己的集群,或者你可以使用下面任意一个 Kubernetes 工具构建:
要获知版本信息,请输入
kubectl version.
在你开始此练习前,请先练习
为节点广播扩展资源 。
在那个练习中将配置你的一个节点来广播 dongle 资源。
给 Pod 分派扩展资源 要请求扩展资源,需要在你的容器清单中包括 resources:requests 字段。
扩展资源可以使用任何完全限定名称,只是不能使用 *.kubernetes.io/。
有效的扩展资源名的格式为 example.com/foo,其中 example.com 应被替换为
你的组织的域名,而 foo 则是描述性的资源名称。
下面是包含一个容器的 Pod 配置文件:
apiVersion : v1
kind : Pod
metadata :
name : extended-resource-demo
spec :
containers :
- name : extended-resource-demo-ctr
image : nginx
resources :
requests :
example.com/dongle : 3
limits :
example.com/dongle : 3
在配置文件中,你可以看到容器请求了 3 个 dongles。
创建 Pod:
kubectl apply -f https://k8s.io/examples/pods/resource/extended-resource-pod.yaml
检查 Pod 是否运行正常:
kubectl get pod extended-resource-demo
描述 Pod:
kubectl describe pod extended-resource-demo
输出结果显示 dongle 请求如下:
Limits :
example.com/dongle : 3
Requests :
example.com/dongle : 3
尝试创建第二个 Pod 下面是包含一个容器的 Pod 配置文件,容器请求了 2 个 dongles。
apiVersion : v1
kind : Pod
metadata :
name : extended-resource-demo-2
spec :
containers :
- name : extended-resource-demo-2-ctr
image : nginx
resources :
requests :
example.com/dongle : 2
limits :
example.com/dongle : 2
Kubernetes 将不能满足 2 个 dongles 的请求,因为第一个 Pod 已经使用了 4 个可用 dongles 中的 3 个。
尝试创建 Pod:
kubectl apply -f https://k8s.io/examples/pods/resource/extended-resource-pod-2.yaml
描述 Pod:
kubectl describe pod extended-resource-demo-2
输出结果表明 Pod 不能被调度,因为没有一个节点上存在两个可用的 dongles。
Conditions:
Type Status
PodScheduled False
...
Events:
...
... Warning FailedScheduling pod (extended-resource-demo-2) failed to fit in any node
fit failure summary on nodes : Insufficient example.com/dongle (1)
查看 Pod 的状态:
kubectl get pod extended-resource-demo-2
输出结果表明 Pod 虽然被创建了,但没有被调度到节点上正常运行。Pod 的状态为 Pending:
NAME READY STATUS RESTARTS AGE
extended-resource-demo-2 0/1 Pending 0 6m
清理 删除本练习中创建的 Pod:
kubectl delete pod extended-resource-demo
kubectl delete pod extended-resource-demo-2
接下来 应用开发者参考 集群管理员参考 4.3.7 - 配置 Pod 以使用卷进行存储 此页面展示了如何配置 Pod 以使用卷进行存储。
只要容器存在,容器的文件系统就会存在,因此当一个容器终止并重新启动,对该容器的文件系统改动将丢失。
对于独立于容器的持久化存储,你可以使用卷 。
这对于有状态应用程序尤为重要,例如键值存储(如 Redis)和数据库。
准备开始
你必须拥有一个 Kubernetes 的集群,同时你的 Kubernetes 集群必须带有 kubectl 命令行工具。
如果你还没有集群,你可以通过 Minikube 构建一
个你自己的集群,或者你可以使用下面任意一个 Kubernetes 工具构建:
要获知版本信息,请输入
kubectl version.
在本练习中,你将创建一个运行 Pod,该 Pod 仅运行一个容器并拥有一个类型为
emptyDir 的卷,
在整个 Pod 生命周期中一直存在,即使 Pod 中的容器被终止和重启。以下是 Pod 的配置:
apiVersion : v1
kind : Pod
metadata :
name : redis
spec :
containers :
- name : redis
image : redis
volumeMounts :
- name : redis-storage
mountPath : /data/redis
volumes :
- name : redis-storage
emptyDir : {}
创建 Pod:
kubectl apply -f https://k8s.io/examples/pods/storage/redis.yaml
验证 Pod 中的容器是否正在运行,然后留意 Pod 的更改:
kubectl get pod redis --watch
输出如下:
NAME READY STATUS RESTARTS AGE
redis 1/1 Running 0 13s
在另一个终端,用 shell 连接正在运行的容器:
kubectl exec -it redis -- /bin/bash
在你的 Shell中,切换到 /data/redis 目录下,然后创建一个文件:
root@redis:/data# cd /data/redis/
root@redis:/data/redis# echo Hello > test-file
在你的 Shell 中,列出正在运行的进程:
root@redis:/data/redis# apt-get update
root@redis:/data/redis# apt-get install procps
root@redis:/data/redis# ps aux
输出类似于:
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
redis 1 0.1 0.1 33308 3828 ? Ssl 00:46 0:00 redis-server *:6379
root 12 0.0 0.0 20228 3020 ? Ss 00:47 0:00 /bin/bash
root 15 0.0 0.0 17500 2072 ? R+ 00:48 0:00 ps aux
在你的 Shell 中,结束 Redis 进程:
root@redis:/data/redis# kill <pid>
其中 <pid> 是 Redis 进程的 ID (PID)。
在你原先终端中,留意 Redis Pod 的更改。最终你将会看到和下面类似的输出:
NAME READY STATUS RESTARTS AGE
redis 1/1 Running 0 13s
redis 0/1 Completed 0 6m
redis 1/1 Running 1 6m
此时,容器已经终止并重新启动。这是因为 Redis Pod 的
restartPolicy
为 Always。
用 Shell 进入重新启动的容器中:
kubectl exec -it redis -- /bin/bash
在你的 Shell 中,进入到 /data/redis 目录下,并确认 test-file 文件是否仍然存在。
root@redis:/data/redis# cd /data/redis/
root@redis:/data/redis# ls
test-file
删除为此练习所创建的 Pod:
接下来 参阅 Volume 。 参阅 Pod 。 除了 emptyDir 提供的本地磁盘存储外,Kubernetes 还支持许多不同的网络附加存储解决方案,
包括 GCE 上的 PD 和 EC2 上的 EBS,它们是关键数据的首选,并将处理节点上的一些细节,
例如安装和卸载设备。了解更多详情请参阅卷 。 4.3.8 - 配置 Pod 以使用 PersistentVolume 作为存储 本文介绍如何配置 Pod 使用
PersistentVolumeClaim
作为存储。
以下是该过程的总结:
你作为集群管理员创建由物理存储支持的 PersistentVolume。你不会将卷与任何 Pod 关联。
你现在以开发人员或者集群用户的角色创建一个 PersistentVolumeClaim,
它将自动绑定到合适的 PersistentVolume。
你创建一个使用 PersistentVolumeClaim 作为存储的 Pod。
准备开始 你需要一个包含单个节点的 Kubernetes 集群,并且必须配置 kubectl 命令行工具以便与集群交互。
如果还没有单节点集群,可以使用
Minikube 创建一个。
. 熟悉持久卷 中的材料。 在你的节点上创建一个 index.html 文件 打开集群中节点的一个 Shell。
如何打开 Shell 取决于集群的设置。
例如,如果你正在使用 Minikube,那么可以通过输入 minikube ssh 来打开节点的 Shell。
在 Shell 中,创建一个 /mnt/data 目录:
# 这里假定你的节点使用 "sudo" 来以超级用户角色执行命令
sudo mkdir /mnt/data
在 /mnt/data 目录中创建一个 index.html 文件:
# 这里再次假定你的节点使用 "sudo" 来以超级用户角色执行命令
sudo sh -c "echo 'Hello from Kubernetes storage' > /mnt/data/index.html"
说明: 如果你的节点使用某工具而不是 sudo 来完成超级用户访问,你可以将上述命令
中的 sudo 替换为该工具的名称。
测试 index.html 文件确实存在:
输出应该是:
Hello from Kubernetes storage
现在你可以关闭节点的 Shell 了。
创建 PersistentVolume 在本练习中,你将创建一个 hostPath 类型的 PersistentVolume。
Kubernetes 支持用于在单节点集群上开发和测试的 hostPath 类型的 PersistentVolume。
hostPath 类型的 PersistentVolume 使用节点上的文件或目录来模拟网络附加存储。
在生产集群中,你不会使用 hostPath。
集群管理员会提供网络存储资源,比如 Google Compute Engine 持久盘卷、NFS 共享卷或 Amazon Elastic Block Store 卷。
集群管理员还可以使用 StorageClasses 来设置动态提供存储 。
下面是 hostPath PersistentVolume 的配置文件:
apiVersion : v1
kind : PersistentVolume
metadata :
name : task-pv-volume
labels :
type : local
spec :
storageClassName : manual
capacity :
storage : 10Gi
accessModes :
- ReadWriteOnce
hostPath :
path : "/mnt/data"
创建 PersistentVolume:
kubectl apply -f https://k8s.io/examples/pods/storage/pv-volume.yaml
查看 PersistentVolume 的信息:
kubectl get pv task-pv-volume
输出结果显示该 PersistentVolume 的状态(STATUS) 为 Available。
这意味着它还没有被绑定给 PersistentVolumeClaim。
NAME CAPACITY ACCESSMODES RECLAIMPOLICY STATUS CLAIM STORAGECLASS REASON AGE
task-pv-volume 10Gi RWO Retain Available manual 4s
创建 PersistentVolumeClaim 下一步是创建一个 PersistentVolumeClaim。
Pod 使用 PersistentVolumeClaim 来请求物理存储。
在本练习中,你将创建一个 PersistentVolumeClaim,它请求至少 3 GB 容量的卷,
该卷至少可以为一个节点提供读写访问。
下面是 PersistentVolumeClaim 的配置文件:
apiVersion : v1
kind : PersistentVolumeClaim
metadata :
name : task-pv-claim
spec :
storageClassName : manual
accessModes :
- ReadWriteOnce
resources :
requests :
storage : 3Gi
创建 PersistentVolumeClaim:
kubectl create -f https://k8s.io/examples/pods/storage/pv-claim.yaml
创建 PersistentVolumeClaim 之后,Kubernetes 控制平面将查找满足申领要求的 PersistentVolume。
如果控制平面找到具有相同 StorageClass 的适当的 PersistentVolume,
则将 PersistentVolumeClaim 绑定到该 PersistentVolume 上。
再次查看 PersistentVolume 信息:
kubectl get pv task-pv-volume
现在输出的 STATUS 为 Bound。
NAME CAPACITY ACCESSMODES RECLAIMPOLICY STATUS CLAIM STORAGECLASS REASON AGE
task-pv-volume 10Gi RWO Retain Bound default/task-pv-claim manual 2m
查看 PersistentVolumeClaim:
kubectl get pvc task-pv-claim
输出结果表明该 PersistentVolumeClaim 绑定了你的 PersistentVolume task-pv-volume。
NAME STATUS VOLUME CAPACITY ACCESSMODES STORAGECLASS AGE
task-pv-claim Bound task-pv-volume 10Gi RWO manual 30s
创建 Pod 下一步是创建一个 Pod, 该 Pod 使用你的 PersistentVolumeClaim 作为存储卷。
下面是 Pod 的 配置文件:
apiVersion : v1
kind : Pod
metadata :
name : task-pv-pod
spec :
volumes :
- name : task-pv-storage
persistentVolumeClaim :
claimName : task-pv-claim
containers :
- name : task-pv-container
image : nginx
ports :
- containerPort : 80
name : "http-server"
volumeMounts :
- mountPath : "/usr/share/nginx/html"
name : task-pv-storage
注意 Pod 的配置文件指定了 PersistentVolumeClaim,但没有指定 PersistentVolume。
对 Pod 而言,PersistentVolumeClaim 就是一个存储卷。
创建 Pod:
kubectl apply -f https://k8s.io/examples/pods/storage/pv-pod.yaml
检查 Pod 中的容器是否运行正常:
kubectl get pod task-pv-pod
打开一个 Shell 访问 Pod 中的容器:
kubectl exec -it task-pv-pod -- /bin/bash
在 Shell 中,验证 nginx 是否正在从 hostPath 卷提供 index.html 文件:
# 一定要在上一步 "kubectl exec" 所返回的 Shell 中执行下面三个命令
root@task-pv-pod:/# apt-get update
root@task-pv-pod:/# apt-get install curl
root@task-pv-pod:/# curl localhost
输出结果是你之前写到 hostPath 卷中的 index.html 文件中的内容:
Hello from Kubernetes storage
如果你看到此消息,则证明你已经成功地配置了 Pod 使用 PersistentVolumeClaim
的存储。
清理 删除 Pod、PersistentVolumeClaim 和 PersistentVolume 对象:
kubectl delete pod task-pv-pod
kubectl delete pvc task-pv-claim
kubectl delete pv task-pv-volume
如果你还没有连接到集群中节点的 Shell,可以按之前所做操作,打开一个新的 Shell。
在节点的 Shell 上,删除你所创建的目录和文件:
# 这里假定你使用 "sudo" 来以超级用户的角色执行命令
sudo rm /mnt/data/index.html
sudo rmdir /mnt/data
你现在可以关闭连接到节点的 Shell。
访问控制 使用组 ID(GID)配置的存储仅允许 Pod 使用相同的 GID 进行写入。
GID 不匹配或缺失将会导致无权访问错误。
为了减少与用户的协调,管理员可以对 PersistentVolume 添加 GID 注解。
这样 GID 就能自动添加到使用 PersistentVolume 的任何 Pod 中。
使用 pv.beta.kubernetes.io/gid 注解的方法如下所示:
kind : PersistentVolume
apiVersion : v1
metadata :
name : pv1
annotations :
pv.beta.kubernetes.io/gid : "1234"
当 Pod 使用带有 GID 注解的 PersistentVolume 时,注解的 GID 会被应用于 Pod 中的所有容器,
应用的方法与 Pod 的安全上下文中指定的 GID 相同。
每个 GID,无论是来自 PersistentVolume 注解还是来自 Pod 规约,都会被应用于每个容器中
运行的第一个进程。
说明: 当 Pod 使用 PersistentVolume 时,与 PersistentVolume 关联的 GID 不会在 Pod
资源本身的对象上出现。
接下来 参考 4.3.9 - 配置 Pod 使用投射卷作存储 本文介绍怎样通过projected 卷将现有的多个卷资源挂载到相同的目录。
当前,secret、configMap、downwardAPI 和 serviceAccountToken 卷可以被投射。
说明: serviceAccountToken 不是一种卷类型
准备开始
你必须拥有一个 Kubernetes 的集群,同时你的 Kubernetes 集群必须带有 kubectl 命令行工具。
如果你还没有集群,你可以通过 Minikube 构建一
个你自己的集群,或者你可以使用下面任意一个 Kubernetes 工具构建:
要获知版本信息,请输入
kubectl version.
为 Pod 配置 projected 卷 本练习中,您将从本地文件来创建包含有用户名和密码的 Secret。然后创建运行一个容器的 Pod,
该 Pod 使用projected 卷将 Secret 挂载到相同的路径下。
下面是 Pod 的配置文件:
apiVersion : v1
kind : Pod
metadata :
name : test-projected-volume
spec :
containers :
- name : test-projected-volume
image : busybox
args :
- sleep
- "86400"
volumeMounts :
- name : all-in-one
mountPath : "/projected-volume"
readOnly : true
volumes :
- name : all-in-one
projected :
sources :
- secret :
name : user
- secret :
name : pass
创建 Secret:
# 创建包含用户名和密码的文件:
echo -n "admin" > ./username.txt
echo -n "1f2d1e2e67df" > ./password.txt-->
# 将上述文件引用到 Secret:
kubectl create secret generic user --from-file= ./username.txt
kubectl create secret generic pass --from-file= ./password.txt
创建 Pod:
kubectl create -f https://k8s.io/examples/pods/storage/projected.yaml
确认 Pod 中的容器运行正常,然后监视 Pod 的变化:
kubectl get --watch pod test-projected-volume
输出结果和下面类似:
NAME READY STATUS RESTARTS AGE
test-projected-volume 1/1 Running 0 14s
在另外一个终端中,打开容器的 shell:
kubectl exec -it test-projected-volume -- /bin/sh
在 shell 中,确认 projected-volume 目录包含你的投射源:
清理 删除 Pod 和 Secret:
kubectl delete pod test-projected-volume
kubectl delete secret user pass
接下来 4.3.10 - 为 Pod 或容器配置安全性上下文 安全上下文(Security Context)定义 Pod 或 Container 的特权与访问控制设置。
安全上下文包括但不限于:
AppArmor :使用程序框架来限制个别程序的权能。Seccomp :过滤进程的系统调用。AllowPrivilegeEscalation:控制进程是否可以获得超出其父进程的特权。
此布尔值直接控制是否为容器进程设置
no_new_privs 标志。
当容器以特权模式运行或者具有 CAP_SYS_ADMIN 权能时,AllowPrivilegeEscalation 总是为 true。 readOnlyRootFilesystem:以只读方式加载容器的根文件系统。 以上条目不是安全上下文设置的完整列表 -- 请参阅
SecurityContext
了解其完整列表。
关于在 Linux 系统中的安全机制的更多信息,可参阅
Linux 内核安全性能力概述 。
准备开始
你必须拥有一个 Kubernetes 的集群,同时你的 Kubernetes 集群必须带有 kubectl 命令行工具。
如果你还没有集群,你可以通过 Minikube 构建一
个你自己的集群,或者你可以使用下面任意一个 Kubernetes 工具构建:
要获知版本信息,请输入
kubectl version.
为 Pod 设置安全性上下文 要为 Pod 设置安全性设置,可在 Pod 规约中包含 securityContext 字段。securityContext 字段值是一个
PodSecurityContext
对象。你为 Pod 所设置的安全性配置会应用到 Pod 中所有 Container 上。
下面是一个 Pod 的配置文件,该 Pod 定义了 securityContext 和一个 emptyDir 卷:
apiVersion : v1
kind : Pod
metadata :
name : security-context-demo
spec :
securityContext :
runAsUser : 1000
runAsGroup : 3000
fsGroup : 2000
volumes :
- name : sec-ctx-vol
emptyDir : {}
containers :
- name : sec-ctx-demo
image : busybox
command : [ "sh" , "-c" , "sleep 1h" ]
volumeMounts :
- name : sec-ctx-vol
mountPath : /data/demo
securityContext :
allowPrivilegeEscalation : false
在配置文件中,runAsUser 字段指定 Pod 中的所有容器内的进程都使用用户 ID 1000
来运行。runAsGroup 字段指定所有容器中的进程都以主组 ID 3000 来运行。
如果忽略此字段,则容器的主组 ID 将是 root(0)。
当 runAsGroup 被设置时,所有创建的文件也会划归用户 1000 和组 3000。
由于 fsGroup 被设置,容器中所有进程也会是附组 ID 2000 的一部分。
卷 /data/demo 及在该卷中创建的任何文件的属主都会是组 ID 2000。
创建该 Pod:
kubectl apply -f https://k8s.io/examples/pods/security/security-context.yaml
检查 Pod 的容器处于运行状态:
kubectl get pod security-context-demo
开启一个 Shell 进入到运行中的容器:
kubectl exec -it security-context-demo -- sh
在你的 Shell 中,列举运行中的进程:
输出显示进程以用户 1000 运行,即 runAsUser 所设置的值:
PID USER TIME COMMAND
1 1000 0:00 sleep 1h
6 1000 0:00 sh
...
在你的 Shell 中,进入 /data 目录列举其内容:
输出显示 /data/demo 目录的组 ID 为 2000,即 fsGroup 的设置值:
drwxrwsrwx 2 root 2000 4096 Jun 6 20:08 demo
在你的 Shell 中,进入到 /data/demo 目录下创建一个文件:
cd demo
echo hello > testfile
列举 /data/demo 目录下的文件:
输出显示 testfile 的组 ID 为 2000,也就是 fsGroup 所设置的值:
-rw-r--r-- 1 1000 2000 6 Jun 6 20:08 testfile
运行下面的命令:
输出为:
uid=1000 gid=3000 groups=2000
你会看到 gid 值为 3000,也就是 runAsGroup 字段的值。
如果 runAsGroup 被忽略,则 gid 会取值 0(root),而进程就能够与 root
用户组所拥有以及要求 root 用户组访问权限的文件交互。
退出你的 Shell:
为 Pod 配置卷访问权限和属主变更策略 FEATURE STATE: Kubernetes v1.20 [beta]
默认情况下,Kubernetes 在挂载一个卷时,会递归地更改每个卷中的内容的属主和访问权限,使之与 Pod
的 securityContext 中指定的 fsGroup 匹配。
对于较大的数据卷,检查和变更属主与访问权限可能会花费很长时间,降低 Pod 启动速度。
你可以在 securityContext 中使用 fsGroupChangePolicy 字段来控制 Kubernetes
检查和管理卷属主和访问权限的方式。
fsGroupChangePolicy - fsGroupChangePolicy 定义在卷被暴露给 Pod 内部之前对其
内容的属主和访问许可进行变更的行为。此字段仅适用于那些支持使用 fsGroup 来
控制属主与访问权限的卷类型。此字段的取值可以是:
OnRootMismatch:只有根目录的属主与访问权限与卷所期望的权限不一致时,
才改变其中内容的属主和访问权限。这一设置有助于缩短更改卷的属主与访问
权限所需要的时间。Always:在挂载卷时总是更改卷中内容的属主和访问权限。例如:
securityContext :
runAsUser : 1000
runAsGroup : 3000
fsGroup : 2000
fsGroupChangePolicy : "OnRootMismatch"
这是一个 Alpha 阶段的功能特性。要使用此特性,需要在 kube-apiserver、kube-controller-manager
和 kubelet 上启用 ConfigurableFSGroupPolicy
特性门控 。
为 Container 设置安全性上下文 若要为 Container 设置安全性配置,可以在 Container 清单中包含 securityContext
字段。securityContext 字段的取值是一个
SecurityContext
对象。你为 Container 设置的安全性配置仅适用于该容器本身,并且所指定的设置
在与 Pod 层面设置的内容发生重叠时,会重载后者。Container 层面的设置不会影响
到 Pod 的卷。
下面是一个 Pod 的配置文件,其中包含一个 Container。Pod 和 Container 都有
securityContext 字段:
apiVersion : v1
kind : Pod
metadata :
name : security-context-demo-2
spec :
securityContext :
runAsUser : 1000
containers :
- name : sec-ctx-demo-2
image : gcr.io/google-samples/node-hello:1.0
securityContext :
runAsUser : 2000
allowPrivilegeEscalation : false
创建该 Pod:
kubectl apply -f https://k8s.io/examples/pods/security/security-context-2.yaml
验证 Pod 中的容器处于运行状态:
kubectl get pod security-context-demo-2
启动一个 Shell 进入到运行中的容器内:
kubectl exec -it security-context-demo-2 -- sh
在你的 Shell 中,列举运行中的进程:
输出显示进程以用户 2000 账号运行。该值是在 Container 的 runAsUser 中设置的。
该设置值重载了 Pod 层面所设置的值 1000。
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
2000 1 0.0 0.0 4336 764 ? Ss 20:36 0:00 /bin/sh -c node server.js
2000 8 0.1 0.5 772124 22604 ? Sl 20:36 0:00 node server.js
...
退出你的 Shell:
为 Container 设置权能 使用 Linux 权能 ,你可以
赋予进程 root 用户所拥有的某些特权,但不必赋予其全部特权。
要为 Container 添加或移除 Linux 权能,可以在 Container 清单的 securityContext 节
包含 capabilities 字段。
首先,查看不包含 capabilities 字段时候会发生什么。
下面是一个配置文件,其中没有添加或移除容器的权能:
apiVersion : v1
kind : Pod
metadata :
name : security-context-demo-3
spec :
containers :
- name : sec-ctx-3
image : gcr.io/google-samples/node-hello:1.0
创建该 Pod:
kubectl apply -f https://k8s.io/examples/pods/security/security-context-3.yaml
验证 Pod 的容器处于运行状态:
kubectl get pod security-context-demo-3
启动一个 Shell 进入到运行中的容器:
kubectl exec -it security-context-demo-3 -- sh
在你的 Shell 中,列举运行中的进程:
输出显示容器中进程 ID(PIDs):
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.0 4336 796 ? Ss 18:17 0:00 /bin/sh -c node server.js
root 5 0.1 0.5 772124 22700 ? Sl 18:17 0:00 node server.js
在你的 Shell 中,查看进程 1 的状态:
输出显示进程的权能位图:
...
CapPrm: 00000000a80425fb
CapEff: 00000000a80425fb
...
记下进程权能位图,之后退出你的 Shell:
接下来运行一个与前例中容器相同的容器,只是这个容器有一些额外的权能设置。
下面是一个 Pod 的配置,其中运行一个容器。配置为容器添加 CAP_NET_ADMIN 和
CAP_SYS_TIME 权能:
apiVersion : v1
kind : Pod
metadata :
name : security-context-demo-4
spec :
containers :
- name : sec-ctx-4
image : gcr.io/google-samples/node-hello:1.0
securityContext :
capabilities :
add : ["NET_ADMIN" , "SYS_TIME" ]
创建 Pod:
kubectl apply -f https://k8s.io/examples/pods/security/security-context-4.yaml
启动一个 Shell,进入到运行中的容器:
kubectl exec -it security-context-demo-4 -- sh
在你的 Shell 中,查看进程 1 的权能:
输出显示的是进程的权能位图:
...
CapPrm: 00000000aa0435fb
CapEff: 00000000aa0435fb
...
比较两个容器的权能位图:
00000000a80425fb
00000000aa0435fb
在第一个容器的权能位图中,位 12 和 25 是没有设置的。在第二个容器中,位 12
和 25 是设置了的。位 12 是 CAP_NET_ADMIN 而位 25 则是 CAP_SYS_TIME。
参见 capability.h
了解权能常数的定义。
说明: Linux 权能常数定义的形式为 CAP_XXX。但是你在 Container 清单中列举权能时,
要将权能名称中的 CAP_ 部分去掉。例如,要添加 CAP_SYS_TIME,可在权能
列表中添加 SYS_TIME。
为容器设置 Seccomp 样板 若要为容器设置 Seccomp 样板(Profile),可在你的 Pod 或 Container 清单的
securityContext 节中包含 seccompProfile 字段。该字段是一个
SeccompProfile
对象,包含 type 和 localhostProfile 属性。
type 的合法选项包括 RuntimeDefault、Unconfined 和 Localhost。
localhostProfile 只能在 type: Localhost 配置下才需要设置。
该字段标明节点上预先配置的样板的路径,路径是相对于 kubelet 所配置的
Seccomp 样板路径(使用 --root-dir 配置)而言的。
下面是一个例子,设置容器使用节点上容器运行时的默认样板作为 Seccomp 样板:
...
securityContext :
seccompProfile :
type : RuntimeDefault
下面是另一个例子,将 Seccomp 的样板设置为位于
<kubelet-根目录>/seccomp/my-profiles/profile-allow.json
的一个预先配置的文件。
...
securityContext :
seccompProfile :
type : Localhost
localhostProfile : my-profiles/profile-allow.json
为 Container 赋予 SELinux 标签 若要给 Container 设置 SELinux 标签,可以在 Pod 或 Container 清单的
securityContext 节包含 seLinuxOptions 字段。
seLinuxOptions 字段的取值是一个
SELinuxOptions
对象。下面是一个应用 SELinux 标签的例子:
...
securityContext :
seLinuxOptions :
level : "s0:c123,c456"
说明: 要指定 SELinux,需要在宿主操作系统中装载 SELinux 安全性模块。
讨论 Pod 的安全上下文适用于 Pod 中的容器,也适用于 Pod 所挂载的卷(如果有的话)。
尤其是,fsGroup 和 seLinuxOptions 按下面的方式应用到挂载卷上:
fsGroup:支持属主管理的卷会被修改,将其属主变更为 fsGroup 所指定的 GID,
并且对该 GID 可写。进一步的细节可参阅
属主变更设计文档 。
seLinuxOptions:支持 SELinux 标签的卷会被重新打标签,以便可被 seLinuxOptions
下所设置的标签访问。通常你只需要设置 level 部分。
该部分设置的是赋予 Pod 中所有容器及卷的
多类别安全性(Multi-Category Security,MCS) 标签。
警告: 在为 Pod 设置 MCS 标签之后,所有带有相同标签的 Pod 可以访问该卷。
如果你需要跨 Pod 的保护,你必须为每个 Pod 赋予独特的 MCS 标签。
清理 删除之前创建的所有 Pod:
kubectl delete pod security-context-demo
kubectl delete pod security-context-demo-2
kubectl delete pod security-context-demo-3
kubectl delete pod security-context-demo-4
接下来 4.3.11 - 为 Pod 配置服务账户 服务账户为 Pod 中运行的进程提供了一个标识。
说明: 本文是服务账户的用户使用介绍,描述服务账号在集群中如何起作用。
你的集群管理员可能已经对你的集群做了定制,因此导致本文中所讲述的内容并不适用。
当你(自然人)访问集群时(例如,使用 kubectl),API 服务器将你的身份验证为
特定的用户帐户(当前这通常是 admin,除非你的集群管理员已经定制了你的集群配置)。
Pod 内的容器中的进程也可以与 api 服务器接触。
当它们进行身份验证时,它们被验证为特定的服务帐户(例如,default)。
准备开始
你必须拥有一个 Kubernetes 的集群,同时你的 Kubernetes 集群必须带有 kubectl 命令行工具。
如果你还没有集群,你可以通过 Minikube 构建一
个你自己的集群,或者你可以使用下面任意一个 Kubernetes 工具构建:
要获知版本信息,请输入
kubectl version.
使用默认的服务账户访问 API 服务器 当你创建 Pod 时,如果没有指定服务账户,Pod 会被指定给命名空间中的 default 服务账户。
如果你查看 Pod 的原始 JSON 或 YAML(例如:kubectl get pods/podname -o yaml),
你可以看到 spec.serviceAccountName 字段已经被自动设置了。
你可以使用自动挂载给 Pod 的服务账户凭据访问 API,
访问集群
中有相关描述。
服务账户的 API 许可取决于你所使用的
鉴权插件和策略 。
在 1.6 以上版本中,你可以通过在服务账户上设置 automountServiceAccountToken: false
来实现不给服务账号自动挂载 API 凭据:
apiVersion : v1
kind : ServiceAccount
metadata :
name : build-robot
automountServiceAccountToken : false
...
在 1.6 以上版本中,你也可以选择不给特定 Pod 自动挂载 API 凭据:
apiVersion : v1
kind : Pod
metadata :
name : my-pod
spec :
serviceAccountName : build-robot
automountServiceAccountToken : false
...
如果 Pod 和服务账户都指定了 automountServiceAccountToken 值,则 Pod 的 spec 优先于服务帐户。
使用多个服务账户 每个命名空间都有一个名为 default 的服务账户资源。
你可以用下面的命令查询这个服务账户以及命名空间中的其他 ServiceAccount 资源:
kubectl get serviceAccounts
输出类似于:
NAME SECRETS AGE
default 1 1d
你可以像这样来创建额外的 ServiceAccount 对象:
kubectl create -f - <<EOF
apiVersion: v1
kind: ServiceAccount
metadata:
name: build-robot
EOF
ServiceAccount 对象的名字必须是一个有效的
DNS 子域名 .
如果你查询服务帐户对象的完整信息,如下所示:
kubectl get serviceaccounts/build-robot -o yaml
输出类似于:
apiVersion : v1
kind : ServiceAccount
metadata :
creationTimestamp : 2015-06-16T00:12:59Z
name : build-robot
namespace : default
resourceVersion : "272500"
uid : 721ab723-13bc-11e5-aec2-42010af0021e
secrets :
- name : build-robot-token-bvbk5
那么你就能看到系统已经自动创建了一个令牌并且被服务账户所引用。
你可以使用授权插件来
设置服务账户的访问许可 。
要使用非默认的服务账户,只需简单的将 Pod 的 spec.serviceAccountName 字段设置为你想用的服务账户名称。
Pod 被创建时服务账户必须存在,否则会被拒绝。
你不能更新已经创建好的 Pod 的服务账户。
你可以清除服务账户,如下所示:
kubectl delete serviceaccount/build-robot
手动创建服务账户 API 令牌 假设我们有一个上面提到的名为 "build-robot" 的服务账户,然后我们手动创建一个新的 Secret。
kubectl create -f - <<EOF
apiVersion: v1
kind: Secret
metadata:
name: build-robot-secret
annotations:
kubernetes.io/service-account.name: build-robot
type: kubernetes.io/service-account-token
EOF
secret/build-robot-secret created
现在,你可以确认新构建的 Secret 中填充了 "build-robot" 服务帐户的 API 令牌。
令牌控制器将清理不存在的服务帐户的所有令牌。
kubectl describe secrets/build-robot-secret
输出类似于:
Name: build-robot-secret
Namespace: default
Labels: <none>
Annotations: kubernetes.io/service-account.name=build-robot
kubernetes.io/service-account.uid=da68f9c6-9d26-11e7-b84e-002dc52800da
Type: kubernetes.io/service-account-token
Data
====
ca.crt: 1338 bytes
namespace: 7 bytes
token: ...
说明: 这里省略了 token 的内容。
为服务账户添加 ImagePullSecrets 创建 ImagePullSecret 将镜像拉取 Secret 添加到服务账号 接着修改命名空间的 default 服务帐户,以将该 Secret 用作 imagePullSecret。
kubectl patch serviceaccount default -p '{"imagePullSecrets": [{"name": "myregistrykey"}]}'
你也可以使用 kubectl edit,或者如下所示手动编辑 YAML 清单:
kubectl get serviceaccounts default -o yaml > ./sa.yaml
sa.yaml 文件的内容类似于:
apiVersion : v1
kind : ServiceAccount
metadata :
creationTimestamp : 2015-08-07T22:02:39Z
name : default
namespace : default
resourceVersion : "243024"
uid : 052fb0f4-3d50-11e5-b066-42010af0d7b6
secrets :
- name : default-token-uudge
使用你常用的编辑器(例如 vi),打开 sa.yaml 文件,删除带有键名
resourceVersion 的行,添加带有 imagePullSecrets: 的行,最后保存文件。
所得到的 sa.yaml 文件类似于:
apiVersion : v1
kind : ServiceAccount
metadata :
creationTimestamp : 2015-08-07T22:02:39Z
name : default
namespace : default
uid : 052fb0f4-3d50-11e5-b066-42010af0d7b6
secrets :
- name : default-token-uudge
imagePullSecrets :
- name : myregistrykey
最后,用新的更新的 sa.yaml 文件替换服务账号。
kubectl replace serviceaccount default -f ./sa.yaml
验证镜像拉取 Secret 已经被添加到 Pod 规约 现在,在当前命名空间中创建的每个使用默认服务账号的新 Pod,新 Pod 都会自动
设置其 .spec.imagePullSecrets 字段:
kubectl run nginx --image= nginx --restart= Never
kubectl get pod nginx -o= jsonpath = '{.spec.imagePullSecrets[0].name}{"\n"}'
输出为:
myregistrykey
服务帐户令牌卷投射 FEATURE STATE: Kubernetes v1.20 [stable]
说明: 为了启用令牌请求投射,你必须为 kube-apiserver 设置以下命令行参数:
--service-account-issuer--service-account-key-file--service-account-signing-key-file--api-audienceskubelet 还可以将服务帐户令牌投影到 Pod 中。
你可以指定令牌的所需属性,例如受众和有效持续时间。
这些属性在默认服务帐户令牌上无法配置。
当删除 Pod 或 ServiceAccount 时,服务帐户令牌也将对 API 无效。
使用名为 ServiceAccountToken 的
ProjectedVolume 类型在 PodSpec 上配置此功能。
要向 Pod 提供具有 "vault" 用户以及两个小时有效期的令牌,可以在 PodSpec 中配置以下内容:
apiVersion : v1
kind : Pod
metadata :
name : nginx
spec :
containers :
- image : nginx
name : nginx
volumeMounts :
- mountPath : /var/run/secrets/tokens
name : vault-token
serviceAccountName : build-robot
volumes :
- name : vault-token
projected :
sources :
- serviceAccountToken :
path : vault-token
expirationSeconds : 7200
audience : vault
创建 Pod:
kubectl create -f https://k8s.io/examples/pods/pod-projected-svc-token.yaml
kubelet 组件会替 Pod 请求令牌并将其保存起来,通过将令牌存储到一个可配置的
路径使之在 Pod 内可用,并在令牌快要到期的时候刷新它。
kubelet 会在令牌存在期达到其 TTL 的 80% 的时候或者令牌生命期超过 24 小时
的时候主动轮换它。
应用程序负责在令牌被轮换时重新加载其内容。对于大多数使用场景而言,周期性地
(例如,每隔 5 分钟)重新加载就足够了。
发现服务账号分发者 FEATURE STATE: Kubernetes v1.20 [beta]
通过启用 ServiceAccountIssuerDiscovery
特性门控 ,
并按前文所述 启用服务账号令牌投射,
可以启用发现服务账号分发者(Service Account Issuer Discovery)这一功能特性。
说明: 分发者的 URL 必须遵从
OIDC 发现规范 。
这意味着 URL 必须使用 https 模式,并且必须在
{service-account-issuer}/.well-known/openid-configuration
路径提供 OpenID 提供者(Provider)配置。
如果 URL 没有遵从这一规范,ServiceAccountIssuerDiscovery 末端就不会被注册,
即使该特性已经被启用。
发现服务账号分发者这一功能使得用户能够用联邦的方式结合使用 Kubernetes
集群(Identity Provider ,标识提供者)与外部系统(relying parties ,
依赖方)所分发的服务账号令牌。
当此功能被启用时,Kubernetes API 服务器会在 /.well-known/openid-configuration
提供一个 OpenID 提供者配置文档,并在 /openid/v1/jwks 处提供与之关联的
JSON Web Key Set(JWKS)。
这里的 OpenID 提供者配置有时候也被称作 发现文档(Discovery Document) 。
特性被启用时,集群也会配置名为 system:service-account-issuer-discovery
的默认 RBAC ClusterRole,但默认情况下不提供角色绑定对象。
举例而言,管理员可以根据其安全性需要以及期望集成的外部系统选择是否将该角色绑定到
system:authenticated 或 system:unauthenticated。
说明: 对 /.well-known/openid-configuration 和 /openid/v1/jwks 路径请求的响应
被设计为与 OIDC 兼容,但不是完全与其一致。
返回的文档仅包含对 Kubernetes 服务账号令牌进行验证所必须的参数。
JWKS 响应包含依赖方可以用来验证 Kubernetes 服务账号令牌的公钥数据。
依赖方先会查询 OpenID 提供者配置,之后使用返回响应中的 jwks_uri 来查找
JWKS。
在很多场合,Kubernetes API 服务器都不会暴露在公网上,不过对于缓存并向外提供 API
服务器响应数据的公开末端而言,用户或者服务提供商可以选择将其暴露在公网上。
在这种环境中,可能会重载 OpenID 提供者配置中的
jwks_uri,使之指向公网上可用的末端地址,而不是 API 服务器的地址。
这时需要向 API 服务器传递 --service-account-jwks-uri 参数。
与分发者 URL 类似,此 JWKS URI 也需要使用 https 模式。
接下来 另请参见:
4.3.12 - 从私有仓库拉取镜像 本文介绍如何使用 Secret 从私有的 Docker 镜像仓库或代码仓库拉取镜像来创建 Pod。
准备开始 你需要 Docker ID 和密码来进行本练习。
登录 Docker 镜像仓库 在个人电脑上,要想拉取私有镜像必须在镜像仓库上进行身份验证。
当出现提示时,输入 Docker 用户名和密码。
登录过程会创建或更新保存有授权令牌的 config.json 文件。
查看 config.json 文件:
cat ~/.docker/config.json
输出结果包含类似于以下内容的部分:
{
"auths" : {
"https://index.docker.io/v1/" : {
"auth" : "c3R...zE2"
}
}
}
说明: 如果使用 Docker 凭证仓库,则不会看到 auth 条目,看到的将是以仓库名称作为值的 credsStore 条目。
在集群中创建保存授权令牌的 Secret Kubernetes 集群使用 docker-registry 类型的 Secret 来通过容器仓库的身份验证,进而提取私有映像。
创建 Secret,命名为 regcred:
kubectl create secret docker-registry regcred \
--docker-server= <你的镜像仓库服务器> \
--docker-username= <你的用户名> \
--docker-password= <你的密码> \
--docker-email= <你的邮箱地址>
在这里:
<your-registry-server> 是你的私有 Docker 仓库全限定域名(FQDN)。
(参考 https://index.docker.io/v1/ 中关于 DockerHub 的部分)<your-name> 是你的 Docker 用户名。<your-pword> 是你的 Docker 密码。<your-email> 是你的 Docker 邮箱。这样你就成功地将集群中的 Docker 凭据设置为名为 regcred 的 Secret。
检查 Secret regcred 要了解你创建的 regcred Secret 的内容,可以用 YAML 格式进行查看:
kubectl get secret regcred --output= yaml
输出和下面类似:
apiVersion : v1
data :
.dockerconfigjson : eyJodHRwczovL2luZGV4L ... J0QUl6RTIifX0=
kind : Secret
metadata :
...
name : regcred
...
type : kubernetes.io/dockerconfigjson
.dockerconfigjson 字段的值是 Docker 凭据的 base64 表示。
要了解 dockerconfigjson 字段中的内容,请将 Secret 数据转换为可读格式:
kubectl get secret regcred --output= "jsonpath={.data.\.dockerconfigjson}" | base64 --decode
输出和下面类似:
{"auths" :{"yourprivateregistry.com" :{"username" :"janedoe" ,"password" :"xxxxxxxxxxx" ,"email" :"jdoe@example.com" ,"auth" :"c3R...zE2" }}}
要了解 auth 字段中的内容,请将 base64 编码过的数据转换为可读格式:
echo "c3R...zE2" | base64 --decode
输出结果中,用户名和密码用 : 链接,类似下面这样:
janedoe:xxxxxxxxxxx
注意,Secret 数据包含与本地 ~/.docker/config.json 文件类似的授权令牌。
这样你就已经成功地将 Docker 凭据设置为集群中的名为 regcred 的 Secret。
创建一个使用你的 Secret 的 Pod 下面是一个 Pod 配置文件,它需要访问 regcred 中的 Docker 凭据:
apiVersion : v1
kind : Pod
metadata :
name : private-reg
spec :
containers :
- name : private-reg-container
image : <your-private-image>
imagePullSecrets :
- name : regcred
下载上述文件:
wget -O my-private-reg-pod.yaml https://k8s.io/examples/pods/private-reg-pod.yaml
在my-private-reg-pod.yaml 文件中,使用私有仓库的镜像路径替换 <your-private-image>,例如:
janedoe/jdoe-private:v1
要从私有仓库拉取镜像,Kubernetes 需要凭证。
配置文件中的 imagePullSecrets 字段表明 Kubernetes 应该通过名为 regcred 的 Secret 获取凭证。
创建使用了你的 Secret 的 Pod,并检查它是否正常运行:
kubectl apply -f my-private-reg-pod.yaml
kubectl get pod private-reg
接下来 4.3.13 - 配置存活、就绪和启动探测器 这篇文章介绍如何给容器配置存活、就绪和启动探测器。
kubelet
使用存活探测器来知道什么时候要重启容器。
例如,存活探测器可以捕捉到死锁(应用程序在运行,但是无法继续执行后面的步骤)。
这样的情况下重启容器有助于让应用程序在有问题的情况下更可用。
kubelet 使用就绪探测器可以知道容器什么时候准备好了并可以开始接受请求流量, 当一个 Pod
内的所有容器都准备好了,才能把这个 Pod 看作就绪了。
这种信号的一个用途就是控制哪个 Pod 作为 Service 的后端。
在 Pod 还没有准备好的时候,会从 Service 的负载均衡器中被剔除的。
kubelet 使用启动探测器可以知道应用程序容器什么时候启动了。
如果配置了这类探测器,就可以控制容器在启动成功后再进行存活性和就绪检查,
确保这些存活、就绪探测器不会影响应用程序的启动。
这可以用于对慢启动容器进行存活性检测,避免它们在启动运行之前就被杀掉。
准备开始
你必须拥有一个 Kubernetes 的集群,同时你的 Kubernetes 集群必须带有 kubectl 命令行工具。
如果你还没有集群,你可以通过 Minikube 构建一
个你自己的集群,或者你可以使用下面任意一个 Kubernetes 工具构建:
要获知版本信息,请输入
kubectl version.
定义存活命令 许多长时间运行的应用程序最终会过渡到断开的状态,除非重新启动,否则无法恢复。
Kubernetes 提供了存活探测器来发现并补救这种情况。
在这篇练习中,你会创建一个 Pod,其中运行一个基于 k8s.gcr.io/busybox 镜像的容器。
下面是这个 Pod 的配置文件。
apiVersion : v1
kind : Pod
metadata :
labels :
test : liveness
name : liveness-exec
spec :
containers :
- name : liveness
image : k8s.gcr.io/busybox
args :
- /bin/sh
- -c
- touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy; sleep 600
livenessProbe :
exec :
command :
- cat
- /tmp/healthy
initialDelaySeconds : 5
periodSeconds : 5
在这个配置文件中,可以看到 Pod 中只有一个容器。
periodSeconds 字段指定了 kubelet 应该每 5 秒执行一次存活探测。
initialDelaySeconds 字段告诉 kubelet 在执行第一次探测前应该等待 5 秒。
kubelet 在容器内执行命令 cat /tmp/healthy 来进行探测。
如果命令执行成功并且返回值为 0,kubelet 就会认为这个容器是健康存活的。
如果这个命令返回非 0 值,kubelet 会杀死这个容器并重新启动它。
当容器启动时,执行如下的命令:
/bin/sh -c "touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy; sleep 600"
这个容器生命的前 30 秒, /tmp/healthy 文件是存在的。
所以在这最开始的 30 秒内,执行命令 cat /tmp/healthy 会返回成功代码。
30 秒之后,执行命令 cat /tmp/healthy 就会返回失败代码。
创建 Pod:
kubectl apply -f https://k8s.io/examples/pods/probe/exec-liveness.yaml
在 30 秒内,查看 Pod 的事件:
kubectl describe pod liveness-exec
输出结果表明还没有存活探测器失败:
FirstSeen LastSeen Count From SubobjectPath Type Reason Message
--------- -------- ----- ---- ------------- -------- ------ -------
24s 24s 1 {default-scheduler } Normal Scheduled Successfully assigned liveness-exec to worker0
23s 23s 1 {kubelet worker0} spec.containers{liveness} Normal Pulling pulling image "k8s.gcr.io/busybox"
23s 23s 1 {kubelet worker0} spec.containers{liveness} Normal Pulled Successfully pulled image "k8s.gcr.io/busybox"
23s 23s 1 {kubelet worker0} spec.containers{liveness} Normal Created Created container with docker id 86849c15382e; Security:[seccomp=unconfined]
23s 23s 1 {kubelet worker0} spec.containers{liveness} Normal Started Started container with docker id 86849c15382e
35 秒之后,再来看 Pod 的事件:
kubectl describe pod liveness-exec
在输出结果的最下面,有信息显示存活探测器失败了,这个容器被杀死并且被重建了。
FirstSeen LastSeen Count From SubobjectPath Type Reason Message
--------- -------- ----- ---- ------------- -------- ------ -------
37s 37s 1 {default-scheduler } Normal Scheduled Successfully assigned liveness-exec to worker0
36s 36s 1 {kubelet worker0} spec.containers{liveness} Normal Pulling pulling image "k8s.gcr.io/busybox"
36s 36s 1 {kubelet worker0} spec.containers{liveness} Normal Pulled Successfully pulled image "k8s.gcr.io/busybox"
36s 36s 1 {kubelet worker0} spec.containers{liveness} Normal Created Created container with docker id 86849c15382e; Security:[seccomp=unconfined]
36s 36s 1 {kubelet worker0} spec.containers{liveness} Normal Started Started container with docker id 86849c15382e
2s 2s 1 {kubelet worker0} spec.containers{liveness} Warning Unhealthy Liveness probe failed: cat: can't open '/tmp/healthy': No such file or directory
再等另外 30 秒,检查看这个容器被重启了:
kubectl get pod liveness-exec
输出结果显示 RESTARTS 的值增加了 1。
NAME READY STATUS RESTARTS AGE
liveness-exec 1/1 Running 1 1m
定义一个存活态 HTTP 请求接口 另外一种类型的存活探测方式是使用 HTTP GET 请求。
下面是一个 Pod 的配置文件,其中运行一个基于 k8s.gcr.io/liveness 镜像的容器。
apiVersion : v1
kind : Pod
metadata :
labels :
test : liveness
name : liveness-http
spec :
containers :
- name : liveness
image : k8s.gcr.io/liveness
args :
- /server
livenessProbe :
httpGet :
path : /healthz
port : 8080
httpHeaders :
- name : Custom-Header
value : Awesome
initialDelaySeconds : 3
periodSeconds : 3
在这个配置文件中,可以看到 Pod 也只有一个容器。
periodSeconds 字段指定了 kubelet 每隔 3 秒执行一次存活探测。
initialDelaySeconds 字段告诉 kubelet 在执行第一次探测前应该等待 3 秒。
kubelet 会向容器内运行的服务(服务会监听 8080 端口)发送一个 HTTP GET 请求来执行探测。
如果服务器上 /healthz 路径下的处理程序返回成功代码,则 kubelet 认为容器是健康存活的。
如果处理程序返回失败代码,则 kubelet 会杀死这个容器并且重新启动它。
任何大于或等于 200 并且小于 400 的返回代码标示成功,其它返回代码都标示失败。
可以在这里看服务的源码 server.go 。
容器存活的最开始 10 秒中,/healthz 处理程序返回一个 200 的状态码。之后处理程序返回 500 的状态码。
http.HandleFunc ("/healthz" , func (w http.ResponseWriter, r * http.Request) {
duration := time.Now ().Sub (started)
if duration.Seconds () > 10 {
w.WriteHeader (500 )
w.Write ([]byte (fmt.Sprintf ("error: %v" , duration.Seconds ())))
} else {
w.WriteHeader (200 )
w.Write ([]byte ("ok" ))
}
})
kubelet 在容器启动之后 3 秒开始执行健康检测。所以前几次健康检查都是成功的。
但是 10 秒之后,健康检查会失败,并且 kubelet 会杀死容器再重新启动容器。
创建一个 Pod 来测试 HTTP 的存活检测:
kubectl apply -f https://k8s.io/examples/pods/probe/http-liveness.yaml
10 秒之后,通过看 Pod 事件来检测存活探测器已经失败了并且容器被重新启动了。
kubectl describe pod liveness-http
在 1.13(包括 1.13版本)之前的版本中,如果在 Pod 运行的节点上设置了环境变量
http_proxy(或者 HTTP_PROXY),HTTP 的存活探测会使用这个代理。
在 1.13 之后的版本中,设置本地的 HTTP 代理环境变量不会影响 HTTP 的存活探测。
定义 TCP 的存活探测 第三种类型的存活探测是使用 TCP 套接字。
通过配置,kubelet 会尝试在指定端口和容器建立套接字链接。
如果能建立连接,这个容器就被看作是健康的,如果不能则这个容器就被看作是有问题的。
apiVersion : v1
kind : Pod
metadata :
name : goproxy
labels :
app : goproxy
spec :
containers :
- name : goproxy
image : k8s.gcr.io/goproxy:0.1
ports :
- containerPort : 8080
readinessProbe :
tcpSocket :
port : 8080
initialDelaySeconds : 5
periodSeconds : 10
livenessProbe :
tcpSocket :
port : 8080
initialDelaySeconds : 15
periodSeconds : 20
如你所见,TCP 检测的配置和 HTTP 检测非常相似。
下面这个例子同时使用就绪和存活探测器。kubelet 会在容器启动 5 秒后发送第一个就绪探测。
这会尝试连接 goproxy 容器的 8080 端口。
如果探测成功,这个 Pod 会被标记为就绪状态,kubelet 将继续每隔 10 秒运行一次检测。
除了就绪探测,这个配置包括了一个存活探测。
kubelet 会在容器启动 15 秒后进行第一次存活探测。
就像就绪探测一样,会尝试连接 goproxy 容器的 8080 端口。
如果存活探测失败,这个容器会被重新启动。
kubectl apply -f https://k8s.io/examples/pods/probe/tcp-liveness-readiness.yaml
15 秒之后,通过看 Pod 事件来检测存活探测器:
kubectl describe pod goproxy
使用命名端口 对于 HTTP 或者 TCP 存活检测可以使用命名的
ContainerPort 。
ports :
- name : liveness-port
containerPort : 8080
hostPort : 8080
livenessProbe :
httpGet :
path : /healthz
port : liveness-port
使用启动探测器保护慢启动容器 有时候,会有一些现有的应用程序在启动时需要较多的初始化时间。
要不影响对引起探测死锁的快速响应,这种情况下,设置存活探测参数是要技巧的。
技巧就是使用一个命令来设置启动探测,针对HTTP 或者 TCP 检测,可以通过设置
failureThreshold * periodSeconds 参数来保证有足够长的时间应对糟糕情况下的启动时间。
所以,前面的例子就变成了:
ports :
- name : liveness-port
containerPort : 8080
hostPort : 8080
livenessProbe :
httpGet :
path : /healthz
port : liveness-port
failureThreshold : 1
periodSeconds : 10
startupProbe :
httpGet :
path : /healthz
port : liveness-port
failureThreshold : 30
periodSeconds : 10
幸亏有启动探测,应用程序将会有最多 5 分钟(30 * 10 = 300s) 的时间来完成它的启动。
一旦启动探测成功一次,存活探测任务就会接管对容器的探测,对容器死锁可以快速响应。
如果启动探测一直没有成功,容器会在 300 秒后被杀死,并且根据 restartPolicy 来设置 Pod 状态。
定义就绪探测器 有时候,应用程序会暂时性的不能提供通信服务。
例如,应用程序在启动时可能需要加载很大的数据或配置文件,或是启动后要依赖等待外部服务。
在这种情况下,既不想杀死应用程序,也不想给它发送请求。
Kubernetes 提供了就绪探测器来发现并缓解这些情况。
容器所在 Pod 上报还未就绪的信息,并且不接受通过 Kubernetes Service 的流量。
说明: 就绪探测器在容器的整个生命周期中保持运行状态。
就绪探测器的配置和存活探测器的配置相似。
唯一区别就是要使用 readinessProbe 字段,而不是 livenessProbe 字段。
readinessProbe :
exec :
command :
- cat
- /tmp/healthy
initialDelaySeconds : 5
periodSeconds : 5
HTTP 和 TCP 的就绪探测器配置也和存活探测器的配置一样的。
就绪和存活探测可以在同一个容器上并行使用。
两者都用可以确保流量不会发给还没有准备好的容器,并且容器会在它们失败的时候被重新启动。
Probe
有很多配置字段,可以使用这些字段精确的控制存活和就绪检测的行为:
initialDelaySeconds:容器启动后要等待多少秒后存活和就绪探测器才被初始化,默认是 0 秒,最小值是 0。periodSeconds:执行探测的时间间隔(单位是秒)。默认是 10 秒。最小值是 1。timeoutSeconds:探测的超时后等待多少秒。默认值是 1 秒。最小值是 1。successThreshold:探测器在失败后,被视为成功的最小连续成功数。默认值是 1。
存活和启动探测的这个值必须是 1。最小值是 1。failureThreshold:当探测失败时,Kubernetes 的重试次数。
存活探测情况下的放弃就意味着重新启动容器。
就绪探测情况下的放弃 Pod 会被打上未就绪的标签。默认值是 3。最小值是 1。在 Kubernetes 1.20 版本之前,exec 探针会忽略 timeoutSeconds:探针会无限期地
持续运行,甚至可能超过所配置的限期,直到返回结果为止。
这一缺陷在 Kubernetes v1.20 版本中得到修复。你可能一直依赖于之前错误的探测行为,
甚至你都没有觉察到这一问题的存在,因为默认的超时值是 1 秒钟。
作为集群管理员,你可以在所有的 kubelet 上禁用 ExecProbeTimeout
特性门控
(将其设置为 false),从而恢复之前版本中的运行行为,之后当集群中所有的
exec 探针都设置了 timeoutSeconds 参数后,移除此标志重载。
如果你有 Pods 受到此默认 1 秒钟超时值的影响,你应该更新 Pod 对应的探针的
超时值,这样才能为最终去除该特性门控做好准备。
当此缺陷被修复之后,在使用 dockershim 容器运行时的 Kubernetes 1.20+
版本中,对于 exec 探针而言,容器中的进程可能会因为超时值的设置保持持续运行,
即使探针返回了失败状态。
注意: 如果就绪态探针的实现不正确,可能会导致容器中进程的数量不断上升。
如果不对其采取措施,很可能导致资源枯竭的状况。
HTTP 探测 HTTP Probes
可以在 httpGet 上配置额外的字段:
host:连接使用的主机名,默认是 Pod 的 IP。也可以在 HTTP 头中设置 “Host” 来代替。scheme :用于设置连接主机的方式(HTTP 还是 HTTPS)。默认是 HTTP。path:访问 HTTP 服务的路径。默认值为 "/"。httpHeaders:请求中自定义的 HTTP 头。HTTP 头字段允许重复。port:访问容器的端口号或者端口名。如果数字必须在 1 ~ 65535 之间。对于 HTTP 探测,kubelet 发送一个 HTTP 请求到指定的路径和端口来执行检测。
除非 httpGet 中的 host 字段设置了,否则 kubelet 默认是给 Pod 的 IP 地址发送探测。
如果 scheme 字段设置为了 HTTPS,kubelet 会跳过证书验证发送 HTTPS 请求。
大多数情况下,不需要设置host 字段。
这里有个需要设置 host 字段的场景,假设容器监听 127.0.0.1,并且 Pod 的 hostNetwork
字段设置为了 true。那么 httpGet 中的 host 字段应该设置为 127.0.0.1。
可能更常见的情况是如果 Pod 依赖虚拟主机,你不应该设置 host 字段,而是应该在
httpHeaders 中设置 Host。
针对 HTTP 探针,kubelet 除了必需的 Host 头部之外还发送两个请求头部字段:
User-Agent 和 Accept。这些头部的默认值分别是 kube-probe/{{ skew latestVersion >}}
(其中 1.24 是 kubelet 的版本号)和 */*。
你可以通过为探测设置 .httpHeaders 来重载默认的头部字段值;例如:
livenessProbe :
httpGet :
httpHeaders :
- name : Accept
value : application/json
startupProbe :
httpGet :
httpHeaders :
- name : User-Agent
value : MyUserAgent
你也可以通过将这些头部字段定义为空值,从请求中去掉这些头部字段。
livenessProbe :
httpGet :
httpHeaders :
- name : Accept
value : ""
startupProbe :
httpGet :
httpHeaders :
- name : User-Agent
value : ""
TCP 探测 对于一次 TCP 探测,kubelet 在节点上(不是在 Pod 里面)建立探测连接,
这意味着你不能在 host 参数上配置服务名称,因为 kubelet 不能解析服务名称。
接下来 参考 4.3.14 - 将 Pod 分配给节点 此页面显示如何将 Kubernetes Pod 分配给 Kubernetes 集群中的特定节点。
准备开始
你必须拥有一个 Kubernetes 的集群,同时你的 Kubernetes 集群必须带有 kubectl 命令行工具。
如果你还没有集群,你可以通过 Minikube 构建一
个你自己的集群,或者你可以使用下面任意一个 Kubernetes 工具构建:
要获知版本信息,请输入
kubectl version.
给节点添加标签 列出集群中的节点
输出类似如下:
NAME STATUS AGE VERSION
worker0 Ready 1d v1.6.0+fff5156
worker1 Ready 1d v1.6.0+fff5156
worker2 Ready 1d v1.6.0+fff5156
选择其中一个节点,为它添加标签:
kubectl label nodes <your-node-name> disktype = ssd
<your-node-name> 是你选择的节点的名称。
验证你选择的节点是否有 disktype=ssd 标签:
kubectl get nodes --show-labels
输出类似如下:
NAME STATUS AGE VERSION LABELS
worker0 Ready 1d v1.6.0+fff5156 ...,disktype=ssd,kubernetes.io/hostname=worker0
worker1 Ready 1d v1.6.0+fff5156 ...,kubernetes.io/hostname=worker1
worker2 Ready 1d v1.6.0+fff5156 ...,kubernetes.io/hostname=worker2
在前面的输出中,你可以看到 worker0 节点有 disktype=ssd 标签。
创建一个调度到你选择的节点的 pod 此 Pod 配置文件描述了一个拥有节点选择器 disktype: ssd 的 Pod。这表明该 Pod 将被调度到
有 disktype=ssd 标签的节点。
apiVersion : v1
kind : Pod
metadata :
name : nginx
labels :
env : test
spec :
containers :
- name : nginx
image : nginx
imagePullPolicy : IfNotPresent
nodeSelector :
disktype : ssd
使用该配置文件去创建一个 pod,该 pod 将被调度到你选择的节点上:
kubectl create -f https://k8s.io/examples/pods/pod-nginx.yaml
验证 pod 是不是运行在你选择的节点上:
kubectl get pods --output= wide
输出类似如下:
NAME READY STATUS RESTARTS AGE IP NODE
nginx 1/1 Running 0 13s 10.200.0.4 worker0
接下来 进一步了解标签和选择器
4.3.15 - 用节点亲和性把 Pods 分配到节点 本页展示在 Kubernetes 集群中,如何使用节点亲和性把 Kubernetes Pod 分配到特定节点。
准备开始
你必须拥有一个 Kubernetes 的集群,同时你的 Kubernetes 集群必须带有 kubectl 命令行工具。
如果你还没有集群,你可以通过 Minikube 构建一
个你自己的集群,或者你可以使用下面任意一个 Kubernetes 工具构建:
您的 Kubernetes 服务器版本必须不低于版本 v1.10.
要获知版本信息,请输入
kubectl version.
给节点添加标签 列出集群中的节点及其标签:
kubectl get nodes --show-labels
输出类似于此:
NAME STATUS ROLES AGE VERSION LABELS
worker0 Ready <none> 1d v1.13.0 ...,kubernetes.io/hostname=worker0
worker1 Ready <none> 1d v1.13.0 ...,kubernetes.io/hostname=worker1
worker2 Ready <none> 1d v1.13.0 ...,kubernetes.io/hostname=worker2
选择一个节点,给它添加一个标签:
kubectl label nodes <your-node-name> disktype = ssd
其中 <your-node-name> 是你所选节点的名称。
验证你所选节点具有 disktype=ssd 标签:
kubectl get nodes --show-labels
输出类似于此:
NAME STATUS ROLES AGE VERSION LABELS
worker0 Ready <none> 1d v1.13.0 ...,disktype=ssd,kubernetes.io/hostname=worker0
worker1 Ready <none> 1d v1.13.0 ...,kubernetes.io/hostname=worker1
worker2 Ready <none> 1d v1.13.0 ...,kubernetes.io/hostname=worker2
在前面的输出中,可以看到 worker0 节点有一个 disktype=ssd 标签。
依据强制的节点亲和性调度 Pod 下面清单描述了一个 Pod,它有一个节点亲和性配置 requiredDuringSchedulingIgnoredDuringExecution,disktype=ssd。
这意味着 pod 只会被调度到具有 disktype=ssd 标签的节点上。
apiVersion : v1
kind : Pod
metadata :
name : nginx
spec :
affinity :
nodeAffinity :
requiredDuringSchedulingIgnoredDuringExecution :
nodeSelectorTerms :
- matchExpressions :
- key : disktype
operator : In
values :
- ssd
containers :
- name : nginx
image : nginx
imagePullPolicy : IfNotPresent
执行(Apply)此清单来创建一个调度到所选节点上的 Pod:
kubectl apply -f https://k8s.io/examples/pods/pod-nginx-required-affinity.yaml
验证 pod 已经在所选节点上运行:
kubectl get pods --output= wide
输出类似于此:
NAME READY STATUS RESTARTS AGE IP NODE
nginx 1/1 Running 0 13s 10.200.0.4 worker0
使用首选的节点亲和性调度 Pod 本清单描述了一个Pod,它有一个节点亲和性设置 preferredDuringSchedulingIgnoredDuringExecution,disktype: ssd。
这意味着 pod 将首选具有 disktype=ssd 标签的节点。
apiVersion : v1
kind : Pod
metadata :
name : nginx
spec :
affinity :
nodeAffinity :
preferredDuringSchedulingIgnoredDuringExecution :
- weight : 1
preference :
matchExpressions :
- key : disktype
operator : In
values :
- ssd
containers :
- name : nginx
image : nginx
imagePullPolicy : IfNotPresent
执行此清单创建一个会调度到所选节点上的 Pod:
kubectl apply -f https://k8s.io/examples/pods/pod-nginx-preferred-affinity.yaml
验证 pod 是否在所选节点上运行:
kubectl get pods --output= wide
输出类似于此:
NAME READY STATUS RESTARTS AGE IP NODE
nginx 1/1 Running 0 13s 10.200.0.4 worker0
接下来 进一步了解
节点亲和性 .
4.3.16 - 配置 Pod 初始化 本文介绍在应用容器运行前,怎样利用 Init 容器初始化 Pod。
准备开始
你必须拥有一个 Kubernetes 的集群,同时你的 Kubernetes 集群必须带有 kubectl 命令行工具。
如果你还没有集群,你可以通过 Minikube 构建一
个你自己的集群,或者你可以使用下面任意一个 Kubernetes 工具构建:
要获知版本信息,请输入
kubectl version.
创建一个包含 Init 容器的 Pod 本例中你将创建一个包含一个应用容器和一个 Init 容器的 Pod。Init 容器在应用容器启动前运行完成。
下面是 Pod 的配置文件:
apiVersion : v1
kind : Pod
metadata :
name : init-demo
spec :
containers :
- name : nginx
image : nginx
ports :
- containerPort : 80
volumeMounts :
- name : workdir
mountPath : /usr/share/nginx/html
# These containers are run during pod initialization
initContainers :
- name : install
image : busybox
command :
- wget
- "-O"
- "/work-dir/index.html"
- http://info.cern.ch
volumeMounts :
- name : workdir
mountPath : "/work-dir"
dnsPolicy : Default
volumes :
- name : workdir
emptyDir : {}
配置文件中,你可以看到应用容器和 Init 容器共享了一个卷。
Init 容器将共享卷挂载到了 /work-dir 目录,应用容器将共享卷挂载到了 /usr/share/nginx/html 目录。
Init 容器执行完下面的命令就终止:
wget -O /work-dir/index.html http://info.cern.ch
请注意 Init 容器在 nginx 服务器的根目录写入 index.html。
创建 Pod:
kubectl create -f https://k8s.io/examples/pods/init-containers.yaml
检查 nginx 容器运行正常:
kubectl get pod init-demo
结果表明 nginx 容器运行正常:
NAME READY STATUS RESTARTS AGE
init-demo 1/1 Running 0 1m
通过 shell 进入 init-demo Pod 中的 nginx 容器:
kubectl exec -it init-demo -- /bin/bash
在 shell 中,发送个 GET 请求到 nginx 服务器:
root@nginx:~# apt-get update
root@nginx:~# apt-get install curl
root@nginx:~# curl localhost
结果表明 nginx 正在为 Init 容器编写的 web 页面服务:
<html><head></head><body><header>
<title>http://info.cern.ch</title>
</header>
<h1>http://info.cern.ch - home of the first website</h1>
...
<li><a href="http://info.cern.ch/hypertext/WWW/TheProject.html">Browse the first website</a></li>
...
接下来 4.3.17 - 为容器的生命周期事件设置处理函数 这个页面将演示如何为容器的生命周期事件挂接处理函数。Kubernetes 支持 postStart 和 preStop 事件。
当一个容器启动后,Kubernetes 将立即发送 postStart 事件;在容器被终结之前,
Kubernetes 将发送一个 preStop 事件。容器可以为每个事件指定一个处理程序。
准备开始
你必须拥有一个 Kubernetes 的集群,同时你的 Kubernetes 集群必须带有 kubectl 命令行工具。
如果你还没有集群,你可以通过 Minikube 构建一
个你自己的集群,或者你可以使用下面任意一个 Kubernetes 工具构建:
要获知版本信息,请输入
kubectl version.
定义 postStart 和 preStop 处理函数 在本练习中,你将创建一个包含一个容器的 Pod,该容器为 postStart 和 preStop 事件提供对应的处理函数。
下面是对应 Pod 的配置文件:
apiVersion : v1
kind : Pod
metadata :
name : lifecycle-demo
spec :
containers :
- name : lifecycle-demo-container
image : nginx
lifecycle :
postStart :
exec :
command : ["/bin/sh" , "-c" , "echo Hello from the postStart handler > /usr/share/message" ]
preStop :
exec :
command : ["/bin/sh" ,"-c" ,"nginx -s quit; while killall -0 nginx; do sleep 1; done" ]
在上述配置文件中,你可以看到 postStart 命令在容器的 /usr/share 目录下写入文件 message。
命令 preStop 负责优雅地终止 nginx 服务。当因为失效而导致容器终止时,这一处理方式很有用。
创建 Pod:
kubectl apply -f https://k8s.io/examples/pods/lifecycle-events.yaml
验证 Pod 中的容器已经运行:
kubectl get pod lifecycle-demo
使用 shell 连接到你的 Pod 里的容器:
kubectl exec -it lifecycle-demo -- /bin/bash
在 shell 中,验证 postStart 处理函数创建了 message 文件:
root@lifecycle-demo:/# cat /usr/share/message
命令行输出的是 postStart 处理函数所写入的文本
Hello from the postStart handler
讨论 Kubernetes 在容器创建后立即发送 postStart 事件。
然而,postStart 处理函数的调用不保证早于容器的入口点(entrypoint)
的执行。postStart 处理函数与容器的代码是异步执行的,但 Kubernetes
的容器管理逻辑会一直阻塞等待 postStart 处理函数执行完毕。
只有 postStart 处理函数执行完毕,容器的状态才会变成
RUNNING。
Kubernetes 在容器结束前立即发送 preStop 事件。除非 Pod 宽限期限超时,Kubernetes 的容器管理逻辑
会一直阻塞等待 preStop 处理函数执行完毕。更多的相关细节,可以参阅
Pods 的结束 。
说明: Kubernetes 只有在 Pod
结束(Terminated) 的时候才会发送 preStop 事件,
这意味着在 Pod
完成(Completed) 时
preStop 的事件处理逻辑不会被触发。这个限制在
issue #55087 中被追踪。
接下来 参考 4.3.18 - 配置 Pod 使用 ConfigMap ConfigMap 允许你将配置文件与镜像文件分离,以使容器化的应用程序具有可移植性。
本页提供了一系列使用示例,这些示例演示了如何创建 ConfigMap 以及配置 Pod
使用存储在 ConfigMap 中的数据。
准备开始
你必须拥有一个 Kubernetes 的集群,同时你的 Kubernetes 集群必须带有 kubectl 命令行工具。
如果你还没有集群,你可以通过 Minikube 构建一
个你自己的集群,或者你可以使用下面任意一个 Kubernetes 工具构建:
要获知版本信息,请输入
kubectl version.
创建 ConfigMap 你可以使用 kubectl create configmap 或者在 kustomization.yaml 中的 ConfigMap 生成器
来创建 ConfigMap。注意,kubectl 从 1.14 版本开始支持 kustomization.yaml。
使用 kubectl create configmap 创建 ConfigMap 你可以使用 kubectl create configmap 命令基于
目录 、文件
或者字面值 来创建 ConfigMap:
kubectl create configmap <map-name> <data-source>
其中,<map-name> 是要设置的 ConfigMap 名称,<data-source> 是要从中提取数据的目录、
文件或者字面值。
ConfigMap 对象的名称必须是合法的
DNS 子域名 .
在你基于文件来创建 ConfigMap 时,<data-source> 中的键名默认取自
文件的基本名,而对应的值则默认为文件的内容。
你可以使用kubectl describe 或者
kubectl get 获取有关 ConfigMap 的信息。
基于目录创建 ConfigMap 你可以使用 kubectl create configmap 基于同一目录中的多个文件创建 ConfigMap。
当你基于目录来创建 ConfigMap 时,kubectl 识别目录下基本名可以作为合法键名的
文件,并将这些文件打包到新的 ConfigMap 中。普通文件之外的所有目录项都会被
忽略(例如,子目录、符号链接、设备、管道等等)。
例如:
# 创建本地目录
mkdir -p configure-pod-container/configmap/
# 将实例文件下载到 `configure-pod-container/configmap/` 目录
wget https://kubernetes.io/examples/configmap/game.properties -O configure-pod-container/configmap/game.properties
wget https://kubernetes.io/examples/configmap/ui.properties -O configure-pod-container/configmap/ui.properties
# 创建 configmap
kubectl create configmap game-config --from-file= configure-pod-container/configmap/
以上命令将 configure-pod-container/configmap 目录下的所有文件,也就是
game.properties 和 ui.properties 打包到 game-config ConfigMap
中。你可以使用下面的命令显示 ConfigMap 的详细信息:
kubectl describe configmaps game-config
输出类似以下内容:
Name: game-config
Namespace: default
Labels: <none>
Annotations: <none>
Data
====
game.properties:
----
enemies=aliens
lives=3
enemies.cheat=true
enemies.cheat.level=noGoodRotten
secret.code.passphrase=UUDDLRLRBABAS
secret.code.allowed=true
secret.code.lives=30
ui.properties:
----
color.good=purple
color.bad=yellow
allow.textmode=true
how.nice.to.look=fairlyNice
configure-pod-container/configmap/ 目录中的 game.properties 和 ui.properties
文件出现在 ConfigMap 的 data 部分。
kubectl get configmaps game-config -o yaml
输出类似以下内容:
apiVersion : v1
kind : ConfigMap
metadata :
creationTimestamp : 2016-02-18T18:52:05Z
name : game-config
namespace : default
resourceVersion : "516"
selfLink : /api/v1/namespaces/default/configmaps/game-config
uid : b4952dc3-d670-11e5-8cd0-68f728db1985
data :
game.properties : |
enemies=aliens
lives=3
enemies.cheat=true
enemies.cheat.level=noGoodRotten
secret.code.passphrase=UUDDLRLRBABAS
secret.code.allowed=true
secret.code.lives=30
ui.properties : |
color.good=purple
color.bad=yellow
allow.textmode=true
how.nice.to.look=fairlyNice
基于文件创建 ConfigMap 你可以使用 kubectl create configmap 基于单个文件或多个文件创建 ConfigMap。
例如:
kubectl create configmap game-config-2 --from-file= configure-pod-container/configmap/game.properties
将产生以下 ConfigMap:
kubectl describe configmaps game-config-2
输出类似以下内容:
Name: game-config-2
Namespace: default
Labels: <none>
Annotations: <none>
Data
====
game.properties:
----
enemies=aliens
lives=3
enemies.cheat=true
enemies.cheat.level=noGoodRotten
secret.code.passphrase=UUDDLRLRBABAS
secret.code.allowed=true
secret.code.lives=30
你可以多次使用 --from-file 参数,从多个数据源创建 ConfigMap。
kubectl create configmap game-config-2 --from-file= configure-pod-container/configmap/game.properties --from-file= configure-pod-container/configmap/ui.properties
描述上面创建的 game-config-2 configmap
kubectl describe configmaps game-config-2
输出类似以下内容:
Name: game-config-2
Namespace: default
Labels: <none>
Annotations: <none>
Data
====
game.properties:
----
enemies=aliens
lives=3
enemies.cheat=true
enemies.cheat.level=noGoodRotten
secret.code.passphrase=UUDDLRLRBABAS
secret.code.allowed=true
secret.code.lives=30
ui.properties:
----
color.good=purple
color.bad=yellow
allow.textmode=true
how.nice.to.look=fairlyNice
使用 --from-env-file 选项从环境文件创建 ConfigMap,例如:
Env 文件包含环境变量列表。
其中适用以下语法规则:
Env 文件中的每一行必须为 VAR=VAL 格式。 以#开头的行(即注释)将被忽略。 空行将被忽略。 引号不会被特殊处理(即它们将成为 ConfigMap 值的一部分)。 将示例文件下载到 configure-pod-container/configmap/ 目录
wget https://kubernetes.io/examples/configmap/game-env-file.properties -O configure-pod-container/configmap/game-env-file.properties
env 文件 game-env-file.properties 如下所示:
cat configure-pod-container/configmap/game-env-file.properties
enemies=aliens
lives=3
allowed="true"
kubectl create configmap game-config-env-file \
--from-env-file= configure-pod-container/configmap/game-env-file.properties
将产生以下 ConfigMap:
kubectl get configmap game-config-env-file -o yaml
输出类似以下内容:
apiVersion : v1
kind : ConfigMap
metadata :
creationTimestamp : 2017-12-27T18:36:28Z
name : game-config-env-file
namespace : default
resourceVersion : "809965"
selfLink : /api/v1/namespaces/default/configmaps/game-config-env-file
uid : d9d1ca5b-eb34-11e7-887b-42010a8002b8
data :
allowed : '"true"'
enemies : aliens
lives : "3"
注意: 当多次使用 --from-env-file 来从多个数据源创建 ConfigMap 时,仅仅最后一个 env 文件有效。
下面是一个多次使用 --from-env-file 参数的示例:
# 将样本文件下载到 `configure-pod-container/configmap/` 目录
wget https://k8s.io/examples/configmap/ui-env-file.properties -O configure-pod-container/configmap/ui-env-file.properties
# 创建 configmap
kubectl create configmap config-multi-env-files \
--from-env-file= configure-pod-container/configmap/game-env-file.properties \
--from-env-file= configure-pod-container/configmap/ui-env-file.properties
将产生以下 ConfigMap:
kubectl get configmap config-multi-env-files -o yaml
输出类似以下内容:
apiVersion : v1
kind : ConfigMap
metadata :
creationTimestamp : 2017-12-27T18:38:34Z
name : config-multi-env-files
namespace : default
resourceVersion : "810136"
selfLink : /api/v1/namespaces/default/configmaps/config-multi-env-files
uid : 252c4572-eb35-11e7-887b-42010a8002b8
data :
color : purple
how : fairlyNice
textmode : "true"
定义从文件创建 ConfigMap 时要使用的键 在使用 --from-file 参数时,你可以定义在 ConfigMap 的 data 部分出现键名,
而不是按默认行为使用文件名:
kubectl create configmap game-config-3 --from-file= <my-key-name>= <path-to-file>
<my-key-name> 是你要在 ConfigMap 中使用的键名,<path-to-file> 是你想要键表示数据源文件的位置。
例如:
kubectl create configmap game-config-3 --from-file= game-special-key= configure-pod-container/configmap/game.properties
将产生以下 ConfigMap:
kubectl get configmaps game-config-3 -o yaml
输出类似以下内容:
apiVersion : v1
kind : ConfigMap
metadata :
creationTimestamp : 2016-02-18T18:54:22Z
name : game-config-3
namespace : default
resourceVersion : "530"
selfLink : /api/v1/namespaces/default/configmaps/game-config-3
uid : 05f8da22-d671-11e5-8cd0-68f728db1985
data :
game-special-key : |
enemies=aliens
lives=3
enemies.cheat=true
enemies.cheat.level=noGoodRotten
secret.code.passphrase=UUDDLRLRBABAS
secret.code.allowed=true
secret.code.lives=30
根据字面值创建 ConfigMap 你可以将 kubectl create configmap 与 --from-literal 参数一起使用,从命令行定义文字值:
kubectl create configmap special-config --from-literal= special.how= very --from-literal= special.type= charm
你可以传入多个键值对。命令行中提供的每对键值在 ConfigMap 的 data 部分中均表示为单独的条目。
kubectl get configmaps special-config -o yaml
输出类似以下内容:
apiVersion : v1
kind : ConfigMap
metadata :
creationTimestamp : 2016-02-18T19:14:38Z
name : special-config
namespace : default
resourceVersion : "651"
selfLink : /api/v1/namespaces/default/configmaps/special-config
uid : dadce046-d673-11e5-8cd0-68f728db1985
data :
special.how : very
special.type : charm
基于生成器创建 ConfigMap 自 1.14 开始,kubectl 开始支持 kustomization.yaml。
你还可以基于生成器创建 ConfigMap,然后将其应用于 API 服务器上创建对象。
生成器应在目录内的 kustomization.yaml 中指定。
基于文件生成 ConfigMap 例如,要从 configure-pod-container/configmap/kubectl/game.properties 文件生成一个 ConfigMap:
# 创建包含 ConfigMapGenerator 的 kustomization.yaml 文件
cat <<EOF >./kustomization.yaml
configMapGenerator:
- name: game-config-4
files:
- configure-pod-container/configmap/kubectl/game.properties
EOF
使用 kustomization 目录创建 ConfigMap 对象:
configmap/game-config-4-m9dm2f92bt created
你可以检查 ConfigMap 是这样创建的:
NAME DATA AGE
game-config-4-m9dm2f92bt 1 37s
kubectl describe configmaps/game-config-4-m9dm2f92bt
Name: game-config-4-m9dm2f92bt
Namespace: default
Labels: <none>
Annotations: kubectl.kubernetes.io/last-applied-configuration:
{"apiVersion":"v1","data":{"game.properties":"enemies=aliens\nlives=3\nenemies.cheat=true\nenemies.cheat.level=noGoodRotten\nsecret.code.p...
Data
====
game.properties:
----
enemies=aliens
lives=3
enemies.cheat=true
enemies.cheat.level=noGoodRotten
secret.code.passphrase=UUDDLRLRBABAS
secret.code.allowed=true
secret.code.lives=30
Events: <none>
请注意,生成的 ConfigMap 名称具有通过对内容进行散列而附加的后缀,
这样可以确保每次修改内容时都会生成新的 ConfigMap。
定义从文件生成 ConfigMap 时要使用的键 在 ConfigMap 生成器,你可以定义一个非文件名的键名。
例如,从 configure-pod-container/configmap/game.properties 文件生成 ConfigMap,
但使用 game-special-key 作为键名:
# 创建包含 ConfigMapGenerator 的 kustomization.yaml 文件
cat <<EOF >./kustomization.yaml
configMapGenerator:
- name: game-config-5
files:
- game-special-key=configure-pod-container/configmap/kubectl/game.properties
EOF
使用 Kustomization 目录创建 ConfigMap 对象。
configmap/game-config-5-m67dt67794 created
从字面值生成 ConfigMap 要基于字符串 special.type=charm 和 special.how=very 生成 ConfigMap,
可以在 kusotmization.yaml 中配置 ConfigMap 生成器:
# 创建带有 ConfigMapGenerator 的 kustomization.yaml 文件
cat <<EOF >./kustomization.yaml
configMapGenerator:
- name: special-config-2
literals:
- special.how=very
- special.type=charm
EOF
应用 Kustomization 目录创建 ConfigMap 对象。
configmap/special-config-2-c92b5mmcf2 created
使用 ConfigMap 数据定义容器环境变量 使用单个 ConfigMap 中的数据定义容器环境变量 在 ConfigMap 中将环境变量定义为键值对:
kubectl create configmap special-config --from-literal= special.how= very
将 ConfigMap 中定义的 special.how 值分配给 Pod 规范中的 SPECIAL_LEVEL_KEY 环境变量。
apiVersion : v1
kind : Pod
metadata :
name : dapi-test-pod
spec :
containers :
- name : test-container
image : k8s.gcr.io/busybox
command : [ "/bin/sh" , "-c" , "env" ]
env :
# Define the environment variable
- name : SPECIAL_LEVEL_KEY
valueFrom :
configMapKeyRef :
# The ConfigMap containing the value you want to assign to SPECIAL_LEVEL_KEY
name : special-config
# Specify the key associated with the value
key : special.how
restartPolicy : Never
创建 Pod:
kubectl create -f https://kubernetes.io/examples/pods/pod-single-configmap-env-variable.yaml
现在,Pod 的输出包含环境变量 SPECIAL_LEVEL_KEY=very。
使用来自多个 ConfigMap 的数据定义容器环境变量 与前面的示例一样,首先创建 ConfigMap。
apiVersion : v1
kind : ConfigMap
metadata :
name : special-config
namespace : default
data :
special.how : very
---
apiVersion : v1
kind : ConfigMap
metadata :
name : env-config
namespace : default
data :
log_level : INFO
创建 ConfigMap:
kubectl create -f https://kubernetes.io/examples/configmap/configmaps.yaml
将 ConfigMap 中的所有键值对配置为容器环境变量 说明: Kubernetes v1.6 和更高版本支持此功能。
创建一个包含多个键值对的 ConfigMap。
apiVersion : v1
kind : ConfigMap
metadata :
name : special-config
namespace : default
data :
SPECIAL_LEVEL : very
SPECIAL_TYPE : charm
创建 ConfigMap:
kubectl create -f https://kubernetes.io/examples/configmap/configmap-multikeys.yaml
在 Pod 命令中使用 ConfigMap 定义的环境变量 你可以使用 $(VAR_NAME) Kubernetes 替换语法在容器的 command 和 args 部分中使用 ConfigMap 定义的环境变量。
例如,以下 Pod 规范
apiVersion : v1
kind : Pod
metadata :
name : dapi-test-pod
spec :
containers :
- name : test-container
image : k8s.gcr.io/busybox
command : [ "/bin/sh" , "-c" , "echo $(SPECIAL_LEVEL_KEY) $(SPECIAL_TYPE_KEY)" ]
env :
- name : SPECIAL_LEVEL_KEY
valueFrom :
configMapKeyRef :
name : special-config
key : SPECIAL_LEVEL
- name : SPECIAL_TYPE_KEY
valueFrom :
configMapKeyRef :
name : special-config
key : SPECIAL_TYPE
restartPolicy : Never
通过运行下面命令创建 Pod:
kubectl create -f https://kubernetes.io/examples/pods/pod-configmap-env-var-valueFrom.yaml
在 test-container 容器中产生以下输出:
very charm
将 ConfigMap 数据添加到一个卷中 如基于文件创建 ConfigMap 中所述,当你使用
--from-file 创建 ConfigMap 时,文件名成为存储在 ConfigMap 的 data 部分中的键,
文件内容成为键对应的值。
本节中的示例引用了一个名为 special-config 的 ConfigMap,如下所示:
apiVersion : v1
kind : ConfigMap
metadata :
name : special-config
namespace : default
data :
SPECIAL_LEVEL : very
SPECIAL_TYPE : charm
创建 ConfigMap:
kubectl create -f https://kubernetes.io/examples/configmap/configmap-multikeys.yaml
使用存储在 ConfigMap 中的数据填充数据卷 在 Pod 规约的 volumes 部分下添加 ConfigMap 名称。
这会将 ConfigMap 数据添加到指定为 volumeMounts.mountPath 的目录(在本例中为 /etc/config)。
command 部分引用存储在 ConfigMap 中的 special.level。
apiVersion : v1
kind : Pod
metadata :
name : dapi-test-pod
spec :
containers :
- name : test-container
image : k8s.gcr.io/busybox
command : [ "/bin/sh" , "-c" , "ls /etc/config/" ]
volumeMounts :
- name : config-volume
mountPath : /etc/config
volumes :
- name : config-volume
configMap :
# Provide the name of the ConfigMap containing the files you want
# to add to the container
name : special-config
restartPolicy : Never
创建 Pod:
kubectl create -f https://kubernetes.io/examples/pods/pod-configmap-volume.yaml
Pod 运行时,命令 ls /etc/config/ 产生下面的输出:
SPECIAL_LEVEL
SPECIAL_TYPE
注意: 如果在 /etc/config/ 目录中有一些文件,它们将被删除。
说明: 文本数据会使用 UTF-8 字符编码的形式展现为文件。如果使用其他字符编码,
可以使用 binaryData。
将 ConfigMap 数据添加到数据卷中的特定路径 使用 path 字段为特定的 ConfigMap 项目指定预期的文件路径。
在这里,SPECIAL_LEVEL 将挂载在 config-volume 数据卷中 /etc/config/keys 目录下。
apiVersion : v1
kind : Pod
metadata :
name : dapi-test-pod
spec :
containers :
- name : test-container
image : k8s.gcr.io/busybox
command : [ "/bin/sh" ,"-c" ,"cat /etc/config/keys" ]
volumeMounts :
- name : config-volume
mountPath : /etc/config
volumes :
- name : config-volume
configMap :
name : special-config
items :
- key : SPECIAL_LEVEL
path : keys
restartPolicy : Never
创建Pod:
kubectl create -f https://kubernetes.io/examples/pods/pod-configmap-volume-specific-key.yaml
当 pod 运行时,命令 cat /etc/config/keys 产生以下输出:
very
注意: 如前,/etc/config/ 目录中所有先前的文件都将被删除。
映射键以指定路径和文件权限 你可以通过指定键名到特定目录的投射关系,也可以逐个文件地设定访问权限。
Secret 用户指南
中对这一语法提供了解释。
挂载的 ConfigMap 将自动更新 更新已经在数据卷中使用的 ConfigMap 时,已映射的键最终也会被更新。
kubelet 在每次定期同步时都会检查已挂载的 ConfigMap 是否是最新的。
但是,它使用其本地的基于 TTL 的缓存来获取 ConfigMap 的当前值。
因此,从更新 ConfigMap 到将新键映射到 Pod 的总延迟可能与
kubelet 同步周期 + ConfigMap 在 kubelet 中缓存的 TTL 一样长。
说明: 使用 ConfigMap 作为
subPath
的数据卷将不会收到 ConfigMap 更新。
了解 ConfigMap 和 Pod ConfigMap API 资源将配置数据存储为键值对。
数据可以在 Pod 中使用,也可以提供系统组件(如控制器)的配置。
ConfigMap 与 Secret 类似,
但是提供了一种使用不包含敏感信息的字符串的方法。
用户和系统组件都可以在 ConfigMap 中存储配置数据。
说明: ConfigMap 应该引用属性文件,而不是替换它们。可以将 ConfigMap 理解为类似于 Linux
/etc 目录及其内容的东西。例如,如果你从 ConfigMap 创建
Kubernetes 卷 ,则 ConfigMap
中的每个数据项都由该数据卷中的单个文件表示。
ConfigMap 的 data 字段包含配置数据。如下例所示,它可以简单
(如用 --from-literal 的单个属性定义)或复杂
(如用 --from-file 的配置文件或 JSON blob定义)。
apiVersion : v1
kind : ConfigMap
metadata :
creationTimestamp : 2016-02-18T19:14:38Z
name : example-config
namespace : default
data :
# 使用 --from-literal 定义的简单属性
example.property.1 : hello
example.property.2 : world
# 使用 --from-file 定义复杂属性的例子
example.property.file : |-
property.1=value-1
property.2=value-2
property.3=value-3
限制 在 Pod 规范中引用之前,必须先创建一个 ConfigMap(除非将 ConfigMap 标记为"可选")。
如果引用的 ConfigMap 不存在,则 Pod 将不会启动。同样,引用 ConfigMap 中不存在的键也会阻止 Pod 启动。 如果你使用 envFrom 基于 ConfigMap 定义环境变量,那么无效的键将被忽略。
可以启动 Pod,但无效名称将记录在事件日志中(InvalidVariableNames)。
日志消息列出了每个跳过的键。例如:
输出与此类似:
LASTSEEN FIRSTSEEN COUNT NAME KIND SUBOBJECT TYPE REASON SOURCE MESSAGE
0s 0s 1 dapi-test-pod Pod Warning InvalidEnvironmentVariableNames {kubelet, 127.0.0.1} Keys [1badkey, 2alsobad] from the EnvFrom configMap default/myconfig were skipped since they are considered invalid environment variable names.
ConfigMap 位于特定的名字空间
中。每个 ConfigMap 只能被同一名字空间中的 Pod 引用. 你不能将 ConfigMap 用于 静态 Pod ,
因为 Kubernetes 不支持这种用法。 接下来 4.3.19 - 在 Pod 中的容器之间共享进程命名空间 FEATURE STATE: Kubernetes v1.17 [stable]
此页面展示如何为 pod 配置进程命名空间共享。
当启用进程命名空间共享时,容器中的进程对该 pod 中的所有其他容器都是可见的。
您可以使用此功能来配置协作容器,比如日志处理 sidecar 容器,或者对那些不包含诸如 shell 等调试实用工具的镜像进行故障排查。
准备开始
你必须拥有一个 Kubernetes 的集群,同时你的 Kubernetes 集群必须带有 kubectl 命令行工具。
如果你还没有集群,你可以通过 Minikube 构建一
个你自己的集群,或者你可以使用下面任意一个 Kubernetes 工具构建:
您的 Kubernetes 服务器版本必须不低于版本 v1.10.
要获知版本信息,请输入
kubectl version.
配置 Pod 进程命名空间共享使用 v1.PodSpec 中的 ShareProcessNamespace 字段启用。例如:
apiVersion : v1
kind : Pod
metadata :
name : nginx
spec :
shareProcessNamespace : true
containers :
- name : nginx
image : nginx
- name : shell
image : busybox
securityContext :
capabilities :
add :
- SYS_PTRACE
stdin : true
tty : true
在集群中创建 nginx pod:
kubectl apply -f https://k8s.io/examples/pods/share-process-namespace.yaml
获取容器 shell,执行 ps:
kubectl attach -it nginx -c shell
如果没有看到命令提示符,请按 enter 回车键。
/ # ps ax
PID USER TIME COMMAND
1 root 0:00 /pause
8 root 0:00 nginx: master process nginx -g daemon off;
14 101 0:00 nginx: worker process
15 root 0:00 sh
21 root 0:00 ps ax
您可以在其他容器中对进程发出信号。例如,发送 SIGHUP 到 nginx 以重启工作进程。这需要 SYS_PTRACE 功能。
/ # kill -HUP 8
/ # ps ax
PID USER TIME COMMAND
1 root 0:00 /pause
8 root 0:00 nginx: master process nginx -g daemon off;
15 root 0:00 sh
22 101 0:00 nginx: worker process
23 root 0:00 ps ax
甚至可以使用 /proc/$pid/root 链接访问另一个容器镜像。
/ # head /proc/8/root/etc/nginx/nginx.conf
user nginx;
worker_processes 1;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
理解进程命名空间共享 Pod 共享许多资源,因此它们共享进程命名空间是很有意义的。
不过,有些容器镜像可能希望与其他容器隔离,因此了解这些差异很重要:
容器进程不再具有 PID 1。 在没有 PID 1 的情况下,一些容器镜像拒绝启动(例如,使用 systemd 的容器),或者拒绝执行 kill -HUP 1 之类的命令来通知容器进程。在具有共享进程命名空间的 pod 中,kill -HUP 1 将通知 pod 沙箱(在上面的例子中是 /pause)。
进程对 pod 中的其他容器可见。 这包括 /proc 中可见的所有信息,例如作为参数或环境变量传递的密码。这些仅受常规 Unix 权限的保护。
容器文件系统通过 /proc/$pid/root 链接对 pod 中的其他容器可见。 这使调试更加容易,但也意味着文件系统安全性只受文件系统权限的保护。
4.3.20 - 创建静态 Pod 静态 Pod 在指定的节点上由 kubelet 守护进程直接管理,不需要
API 服务器 监管。
与由控制面管理的 Pod(例如,Deployment )
不同;kubelet 监视每个静态 Pod(在它崩溃之后重新启动)。
静态 Pod 永远都会绑定到一个指定节点上的 Kubelet 。
kubelet 会尝试通过 Kubernetes API 服务器为每个静态 Pod 自动创建一个
镜像 Pod 。
这意味着节点上运行的静态 Pod 对 API 服务来说是可见的,但是不能通过 API 服务器来控制。
说明: 如果你在运行一个 Kubernetes 集群,并且在每个节点上都运行一个静态 Pod,
就可能需要考虑使用
DaemonSet 替代这种方式。
准备开始
你必须拥有一个 Kubernetes 的集群,同时你的 Kubernetes 集群必须带有 kubectl 命令行工具。
如果你还没有集群,你可以通过 Minikube 构建一
个你自己的集群,或者你可以使用下面任意一个 Kubernetes 工具构建:
要获知版本信息,请输入
kubectl version.
本文假定你在使用 Docker 来运行 Pod,
并且你的节点是运行着 Fedora 操作系统。
其它发行版或者 Kubernetes 部署版本上操作方式可能不一样。
创建静态 Pod 可以通过文件系统上的配置文件
或者 web 网络上的配置文件
来配置静态 Pod。
文件系统上的静态 Pod 声明文件 声明文件是标准的 Pod 定义文件,以 JSON 或者 YAML 格式存储在指定目录。路径设置在
Kubelet 配置文件
的 staticPodPath: <目录> 字段,kubelet 会定期的扫描这个文件夹下的 YAML/JSON
文件来创建/删除静态 Pod。
注意 kubelet 扫描目录的时候会忽略以点开头的文件。
例如:下面是如何以静态 Pod 的方式启动一个简单 web 服务:
选择一个要运行静态 Pod 的节点。在这个例子中选择 my-node1。
选择一个目录,比如在 /etc/kubelet.d 目录来保存 web 服务 Pod 的定义文件,
/etc/kubelet.d/static-web.yaml:
# 在 kubelet 运行的节点上执行以下命令
mkdir /etc/kubelet.d/
cat <<EOF >/etc/kubelet.d/static-web.yaml
apiVersion: v1
kind: Pod
metadata:
name: static-web
labels:
role: myrole
spec:
containers:
- name: web
image: nginx
ports:
- name: web
containerPort: 80
protocol: TCP
EOF
配置这个节点上的 kubelet,使用这个参数执行 --pod-manifest-path=/etc/kubelet.d/。
在 Fedora 上编辑 /etc/kubernetes/kubelet 以包含下行:
KUBELET_ARGS="--cluster-dns=10.254.0.10 --cluster-domain=kube.local --pod-manifest-path=/etc/kubelet.d/"
或者在 Kubelet配置文件
中添加 staticPodPath: <目录>字段。
重启 kubelet。Fedora 上使用下面的命令:
# 在 kubelet 运行的节点上执行以下命令
systemctl restart kubelet
Web 网上的静态 Pod 声明文件 Kubelet 根据 --manifest-url=<URL> 参数的配置定期的下载指定文件,并且转换成
JSON/YAML 格式的 Pod 定义文件。
与文件系统上的清单文件 使用方式类似,kubelet 调度获取清单文件。
如果静态 Pod 的清单文件有改变,kubelet 会应用这些改变。
按照下面的方式来:
创建一个 YAML 文件,并保存在 web 服务上,为 kubelet 生成一个 URL。
apiVersion : v1
kind : Pod
metadata :
name : static-web
labels :
role : myrole
spec :
containers :
- name : web
image : nginx
ports :
- name : web
containerPort : 80
protocol : TCP
通过在选择的节点上使用 --manifest-url=<manifest-url> 配置运行 kubelet。
在 Fedora 添加下面这行到 /etc/kubernetes/kubelet :
KUBELET_ARGS="--cluster-dns=10.254.0.10 --cluster-domain=kube.local --manifest-url=<manifest-url>"
重启 kubelet。在 Fedora 上运行如下命令:
# 在 kubelet 运行的节点上执行以下命令
systemctl restart kubelet
观察静态 pod 的行为 当 kubelet 启动时,会自动启动所有定义的静态 Pod。
当定义了一个静态 Pod 并重新启动 kubelet 时,新的静态 Pod 就应该已经在运行了。
可以在节点上运行下面的命令来查看正在运行的容器(包括静态 Pod):
# 在 kubelet 运行的节点上执行以下命令
docker ps
输出可能会像这样:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
f6d05272b57e nginx:latest "nginx" 8 minutes ago Up 8 minutes k8s_web.6f802af4_static-web-fk-node1_default_67e24ed9466ba55986d120c867395f3c_378e5f3c
可以在 API 服务上看到镜像 Pod:
NAME READY STATUS RESTARTS AGE
static-web-my-node1 1/1 Running 0 2m
说明: 要确保 kubelet 在 API 服务上有创建镜像 Pod 的权限。如果没有,创建请求会被 API 服务拒绝。
可以看
Pod安全策略 。
静态 Pod 上的标签 被传到镜像 Pod。
你可以通过 选择算符 使用这些标签。
如果你用 kubectl 从 API 服务上删除镜像 Pod,kubelet 不会 移除静态 Pod:
kubectl delete pod static-web-my-node1
pod "static-web-my-node1" deleted
可以看到 Pod 还在运行:
NAME READY STATUS RESTARTS AGE
static-web-my-node1 1/1 Running 0 12s
回到 kubelet 运行的节点上,可以手工停止 Docker 容器。
可以看到过了一段时间后 kubelet 会发现容器停止了并且会自动重启 Pod:
# 在 kubelet 运行的节点上执行以下命令
# 把 ID 换为你的容器的 ID
docker stop f6d05272b57e
sleep 20
docker ps
CONTAINER ID IMAGE COMMAND CREATED ...
5b920cbaf8b1 nginx:latest "nginx -g 'daemon of 2 seconds ago ...
动态增加和删除静态 pod 运行中的 kubelet 会定期扫描配置的目录(比如例子中的 /etc/kubelet.d 目录)中的变化,
并且根据文件中出现/消失的 Pod 来添加/删除 Pod。
# 前提是你在用主机文件系统上的静态 Pod 配置文件
# 在 kubelet 运行的节点上执行以下命令
mv /etc/kubelet.d/static-web.yaml /tmp
sleep 20
docker ps
# 可以看到没有 nginx 容器在运行
mv /tmp/static-web.yaml /etc/kubelet.d/
sleep 20
docker ps
CONTAINER ID IMAGE COMMAND CREATED ...
e7a62e3427f1 nginx:latest "nginx -g 'daemon of 27 seconds ago
4.3.21 - 将 Docker Compose 文件转换为 Kubernetes 资源 Kompose 是什么?它是个转换工具,可将 compose(即 Docker Compose)所组装的所有内容
转换成容器编排器(Kubernetes 或 OpenShift)可识别的形式。
更多信息请参考 Kompose 官网 http://kompose.io 。
准备开始
你必须拥有一个 Kubernetes 的集群,同时你的 Kubernetes 集群必须带有 kubectl 命令行工具。
如果你还没有集群,你可以通过 Minikube 构建一
个你自己的集群,或者你可以使用下面任意一个 Kubernetes 工具构建:
要获知版本信息,请输入
kubectl version.
安装 Kompose 我们有很多种方式安装 Kompose。首选方式是从最新的 GitHub 发布页面下载二进制文件。
Kompose 通过 GitHub 发布,发布周期为三星期。
你可以在 GitHub 发布页面
上看到所有当前版本。
# Linux
curl -L https://github.com/kubernetes/kompose/releases/download/v1.22.0/kompose-linux-amd64 -o kompose
# macOS
curl -L https://github.com/kubernetes/kompose/releases/download/v1.22.0/kompose-darwin-amd64 -o kompose
# Windows
curl -L https://github.com/kubernetes/kompose/releases/download/v1.22.0/kompose-windows-amd64.exe -o kompose.exe
chmod +x kompose
sudo mv ./kompose /usr/local/bin/kompose
或者,你可以下载 tar 包 。
用 go get 命令从主分支拉取最新的开发变更的方法安装 Kompose。
go get -u github.com/kubernetes/kompose
Kompose 位于 EPEL CentOS 代码仓库。
如果你还没有安装启用 EPEL 代码仓库,
请运行命令 sudo yum install epel-release。
如果你的系统中已经启用了 EPEL ,
你就可以像安装其他软件包一样安装 Kompose。
sudo yum -y install kompose
Kompose 位于 Fedora 24、25 和 26 的代码仓库。你可以像安装其他软件包一样安装 Kompose。
sudo dnf -y install kompose
在 macOS 上你可以通过 Homebrew 安装 Kompose 的最新版本:
使用 Kompose 再需几步,我们就把你从 Docker Compose 带到 Kubernetes。
你只需要一个现有的 docker-compose.yml 文件。
进入 docker-compose.yml 文件所在的目录。如果没有,请使用下面这个进行测试。
version : "2"
services :
redis-master :
image : k8s.gcr.io/redis:e2e
ports :
- "6379"
redis-slave :
image : gcr.io/google_samples/gb-redisslave:v3
ports :
- "6379"
environment :
- GET_HOSTS_FROM=dns
frontend :
image : gcr.io/google-samples/gb-frontend:v4
ports :
- "80:80"
environment :
- GET_HOSTS_FROM=dns
labels :
kompose.service.type : LoadBalancer
要将 docker-compose.yml 转换为 kubectl 可用的文件,请运行 kompose convert
命令进行转换,然后运行 kubectl create -f <output file> 进行创建。
INFO Kubernetes file "frontend-service.yaml" created
INFO Kubernetes file "frontend-service.yaml" created
INFO Kubernetes file "frontend-service.yaml" created
INFO Kubernetes file "redis-master-service.yaml" created
INFO Kubernetes file "redis-master-service.yaml" created
INFO Kubernetes file "redis-master-service.yaml" created
INFO Kubernetes file "redis-slave-service.yaml" created
INFO Kubernetes file "redis-slave-service.yaml" created
INFO Kubernetes file "redis-slave-service.yaml" created
INFO Kubernetes file "frontend-deployment.yaml" created
INFO Kubernetes file "frontend-deployment.yaml" created
INFO Kubernetes file "frontend-deployment.yaml" created
INFO Kubernetes file "redis-master-deployment.yaml" created
INFO Kubernetes file "redis-master-deployment.yaml" created
INFO Kubernetes file "redis-master-deployment.yaml" created
INFO Kubernetes file "redis-slave-deployment.yaml" created
INFO Kubernetes file "redis-slave-deployment.yaml" created
INFO Kubernetes file "redis-slave-deployment.yaml" created
kubectl apply -f frontend-service.yaml,redis-master-service.yaml,redis-slave-service.yaml,frontend-deployment.yaml,
输出类似于:
service/frontend created
service/redis-master created
service/redis-slave created
deployment.apps/frontend created
deployment.apps/redis-master created
deployment.apps/redis-slave created
你部署的应用在 Kubernetes 中运行起来了。
访问你的应用
如果你在开发过程中使用 minikube,请执行:
minikube service frontend
否则,我们要查看一下你的服务使用了什么 IP!
kubectl describe svc frontend
Name: frontend
Namespace: default
Labels: service=frontend
Selector: service=frontend
Type: LoadBalancer
IP: 10.0.0.183
LoadBalancer Ingress: 192.0.2.89
Port: 80 80/TCP
NodePort: 80 31144/TCP
Endpoints: 172.17.0.4:80
Session Affinity: None
No events.
如果你使用的是云提供商,你的 IP 将在 LoadBalancer Ingress 字段给出。
用户指南 Kompose 支持两种驱动:OpenShift 和 Kubernetes。
你可以通过全局选项 --provider 选择驱动。如果没有指定,
会将 Kubernetes 作为默认驱动。
kompose convertKompose 支持将 V1、V2 和 V3 版本的 Docker Compose 文件转换为 Kubernetes 和 OpenShift 资源对象。
Kubernetes kompose convert 示例 kompose --file docker-voting.yml convert
WARN Unsupported key networks - ignoring
WARN Unsupported key build - ignoring
INFO Kubernetes file "worker-svc.yaml" created
INFO Kubernetes file "db-svc.yaml" created
INFO Kubernetes file "redis-svc.yaml" created
INFO Kubernetes file "result-svc.yaml" created
INFO Kubernetes file "vote-svc.yaml" created
INFO Kubernetes file "redis-deployment.yaml" created
INFO Kubernetes file "result-deployment.yaml" created
INFO Kubernetes file "vote-deployment.yaml" created
INFO Kubernetes file "worker-deployment.yaml" created
INFO Kubernetes file "db-deployment.yaml" created
db-deployment.yaml docker-compose.yml docker-gitlab.yml redis-deployment.yaml result-deployment.yaml vote-deployment.yaml worker-deployment.yaml
db-svc.yaml docker-voting.yml redis-svc.yaml result-svc.yaml vote-svc.yaml worker-svc.yaml
你也可以同时提供多个 docker-compose 文件进行转换:
kompose -f docker-compose.yml -f docker-guestbook.yml convert
INFO Kubernetes file "frontend-service.yaml" created
INFO Kubernetes file "mlbparks-service.yaml" created
INFO Kubernetes file "mongodb-service.yaml" created
INFO Kubernetes file "redis-master-service.yaml" created
INFO Kubernetes file "redis-slave-service.yaml" created
INFO Kubernetes file "frontend-deployment.yaml" created
INFO Kubernetes file "mlbparks-deployment.yaml" created
INFO Kubernetes file "mongodb-deployment.yaml" created
INFO Kubernetes file "mongodb-claim0-persistentvolumeclaim.yaml" created
INFO Kubernetes file "redis-master-deployment.yaml" created
INFO Kubernetes file "redis-slave-deployment.yaml" created
mlbparks-deployment.yaml mongodb-service.yaml redis-slave-service.jsonmlbparks-service.yaml
frontend-deployment.yaml mongodb-claim0-persistentvolumeclaim.yaml redis-master-service.yaml
frontend-service.yaml mongodb-deployment.yaml redis-slave-deployment.yaml
redis-master-deployment.yaml
当提供多个 docker-compose 文件时,配置将会合并。任何通用的配置都将被后续文件覆盖。
OpenShift kompose convert 示例 kompose --provider openshift --file docker-voting.yml convert
WARN [worker] Service cannot be created because of missing port.
INFO OpenShift file "vote-service.yaml" created
INFO OpenShift file "db-service.yaml" created
INFO OpenShift file "redis-service.yaml" created
INFO OpenShift file "result-service.yaml" created
INFO OpenShift file "vote-deploymentconfig.yaml" created
INFO OpenShift file "vote-imagestream.yaml" created
INFO OpenShift file "worker-deploymentconfig.yaml" created
INFO OpenShift file "worker-imagestream.yaml" created
INFO OpenShift file "db-deploymentconfig.yaml" created
INFO OpenShift file "db-imagestream.yaml" created
INFO OpenShift file "redis-deploymentconfig.yaml" created
INFO OpenShift file "redis-imagestream.yaml" created
INFO OpenShift file "result-deploymentconfig.yaml" created
INFO OpenShift file "result-imagestream.yaml" created
kompose 还支持为服务中的构建指令创建 buildconfig。
默认情况下,它使用当前 git 分支的 remote 仓库作为源仓库,使用当前分支作为构建的源分支。
你可以分别使用 --build-repo 和 --build-branch 选项指定不同的源仓库和分支。
kompose --provider openshift --file buildconfig/docker-compose.yml convert
WARN [foo] Service cannot be created because of missing port.
INFO OpenShift Buildconfig using git@github.com:rtnpro/kompose.git::master as source.
INFO OpenShift file "foo-deploymentconfig.yaml" created
INFO OpenShift file "foo-imagestream.yaml" created
INFO OpenShift file "foo-buildconfig.yaml" created
说明: 如果使用 oc create -f 手动推送 Openshift 工件,则需要确保在构建配置工件之前推送
imagestream 工件,以解决 Openshift 的这个问题:https://github.com/openshift/origin/issues/4518 。
kompose upKompose 支持通过 kompose up 直接将你的"复合的(composed)" 应用程序
部署到 Kubernetes 或 OpenShift。
Kubernetes kompose up 示例 kompose --file ./examples/docker-guestbook.yml up
We are going to create Kubernetes deployments and services for your Dockerized application.
If you need different kind of resources, use the 'kompose convert' and 'kubectl create -f' commands instead.
INFO Successfully created service: redis-master
INFO Successfully created service: redis-slave
INFO Successfully created service: frontend
INFO Successfully created deployment: redis-master
INFO Successfully created deployment: redis-slave
INFO Successfully created deployment: frontend
Your application has been deployed to Kubernetes. You can run 'kubectl get deployment,svc,pods' for details.
kubectl get deployment,svc,pods
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
deployment.extensions/frontend 1 1 1 1 4m
deployment.extensions/redis-master 1 1 1 1 4m
deployment.extensions/redis-slave 1 1 1 1 4m
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/frontend ClusterIP 10.0.174.12 <none> 80/TCP 4m
service/kubernetes ClusterIP 10.0.0.1 <none> 443/TCP 13d
service/redis-master ClusterIP 10.0.202.43 <none> 6379/TCP 4m
service/redis-slave ClusterIP 10.0.1.85 <none> 6379/TCP 4m
NAME READY STATUS RESTARTS AGE
pod/frontend-2768218532-cs5t5 1/1 Running 0 4m
pod/redis-master-1432129712-63jn8 1/1 Running 0 4m
pod/redis-slave-2504961300-nve7b 1/1 Running 0 4m
说明: 你必须有一个运行正常的 Kubernetes 集群,该集群具有预先配置的 kubectl 上下文。 此操作仅生成 Deployment 和 Service 对象并将其部署到 Kubernetes。
如果需要部署其他不同类型的资源,请使用 kompose convert 和 kubectl create -f 命令。 OpenShift kompose up 示例 kompose --file ./examples/docker-guestbook.yml --provider openshift up
We are going to create OpenShift DeploymentConfigs and Services for your Dockerized application.
If you need different kind of resources, use the 'kompose convert' and 'oc create -f' commands instead.
INFO Successfully created service: redis-slave
INFO Successfully created service: frontend
INFO Successfully created service: redis-master
INFO Successfully created deployment: redis-slave
INFO Successfully created ImageStream: redis-slave
INFO Successfully created deployment: frontend
INFO Successfully created ImageStream: frontend
INFO Successfully created deployment: redis-master
INFO Successfully created ImageStream: redis-master
Your application has been deployed to OpenShift. You can run 'oc get dc,svc,is' for details.
NAME REVISION DESIRED CURRENT TRIGGERED BY
dc/frontend 0 1 0 config,image(frontend:v4)
dc/redis-master 0 1 0 config,image(redis-master:e2e)
dc/redis-slave 0 1 0 config,image(redis-slave:v1)
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
svc/frontend 172.30.46.64 <none> 80/TCP 8s
svc/redis-master 172.30.144.56 <none> 6379/TCP 8s
svc/redis-slave 172.30.75.245 <none> 6379/TCP 8s
NAME DOCKER REPO TAGS UPDATED
is/frontend 172.30.12.200:5000/fff/frontend
is/redis-master 172.30.12.200:5000/fff/redis-master
is/redis-slave 172.30.12.200:5000/fff/redis-slave v1
说明: 你必须有一个运行正常的 OpenShift 集群,该集群具有预先配置的 oc 上下文 (oc login)。
kompose down你一旦将"复合(composed)" 应用部署到 Kubernetes,kompose down
命令将能帮你通过删除 Deployment 和 Service 对象来删除应用。
如果需要删除其他资源,请使用 'kubectl' 命令。
kompose --file docker-guestbook.yml down
INFO Successfully deleted service: redis-master
INFO Successfully deleted deployment: redis-master
INFO Successfully deleted service: redis-slave
INFO Successfully deleted deployment: redis-slave
INFO Successfully deleted service: frontend
INFO Successfully deleted deployment: frontend
说明: 你必须有一个运行正常的 Kubernetes 集群,该集群具有预先配置的 kubectl 上下文。 构建和推送 Docker 镜像 Kompose 支持构建和推送 Docker 镜像。如果 Docker Compose 文件中使用了 build
关键字,你的镜像将会:
使用文档中指定的 image 键自动构建 Docker 镜像 使用本地凭据推送到正确的 Docker 仓库 使用 Docker Compose 文件示例
version : "2"
services :
foo :
build : "./build"
image : docker.io/foo/bar
使用带有 build 键的 kompose up 命令:
INFO Build key detected. Attempting to build and push image 'docker.io/foo/bar'
INFO Building image 'docker.io/foo/bar' from directory 'build'
INFO Image 'docker.io/foo/bar' from directory 'build' built successfully
INFO Pushing image 'foo/bar:latest' to registry 'docker.io'
INFO Attempting authentication credentials 'https://index.docker.io/v1/
INFO Successfully pushed image 'foo/bar:latest' to registry 'docker.io'
INFO We are going to create Kubernetes Deployments, Services and PersistentVolumeClaims for your Dockerized application. If you need different kind of resources, use the 'kompose convert' and 'kubectl create -f' commands instead.
INFO Deploying application in "default" namespace
INFO Successfully created Service: foo
INFO Successfully created Deployment: foo
Your application has been deployed to Kubernetes. You can run 'kubectl get deployment,svc,pods,pvc' for details.
要想禁用该功能,或者使用 BuildConfig 中的版本(在 OpenShift 中),
可以通过传递 --build (local|build-config|none) 参数来实现。
# 禁止构造和推送 Docker 镜像
kompose up --build none
# 为 OpenShift 生成 Build Config 工件
kompose up --provider openshift --build build-config
其他转换方式 默认的 kompose 转换会生成 yaml 格式的 Kubernetes
Deployment 和
Service 对象。
你可以选择通过 -j 参数生成 json 格式的对象。
你也可以替换生成 Replication Controllers 对象、
Daemon Sets 或
Helm charts。
INFO Kubernetes file "redis-svc.json" created
INFO Kubernetes file "web-svc.json" created
INFO Kubernetes file "redis-deployment.json" created
INFO Kubernetes file "web-deployment.json" created
*-deployment.json 文件中包含 Deployment 对象。
kompose convert --replication-controller
INFO Kubernetes file "redis-svc.yaml" created
INFO Kubernetes file "web-svc.yaml" created
INFO Kubernetes file "redis-replicationcontroller.yaml" created
INFO Kubernetes file "web-replicationcontroller.yaml" created
*-replicationcontroller.yaml 文件包含 Replication Controller 对象。
如果你想指定副本数(默认为 1),可以使用 --replicas 参数:
kompose convert --replication-controller --replicas 3
kompose convert --daemon-set
INFO Kubernetes file "redis-svc.yaml" created
INFO Kubernetes file "web-svc.yaml" created
INFO Kubernetes file "redis-daemonset.yaml" created
INFO Kubernetes file "web-daemonset.yaml" created
*-daemonset.yaml 文件包含 DaemonSet 对象。
如果你想生成 Helm 可用的 Chart,
只需简单的执行下面的命令:
INFO Kubernetes file "web-svc.yaml" created
INFO Kubernetes file "redis-svc.yaml" created
INFO Kubernetes file "web-deployment.yaml" created
INFO Kubernetes file "redis-deployment.yaml" created
chart created in "./docker-compose/"
docker-compose
├── Chart.yaml
├── README.md
└── templates
├── redis-deployment.yaml
├── redis-svc.yaml
├── web-deployment.yaml
└── web-svc.yaml
这个 Chart 结构旨在为构建 Helm Chart 提供框架。
标签 kompose 支持 docker-compose.yml 文件中用于 Kompose 的标签,以便
在转换时明确定义 Service 的行为。
当前支持的选项有:
键 值 kompose.service.type nodeport / clusterip / loadbalancer kompose.service.expose true / hostname
说明: kompose.service.type 标签应该只用 ports 来定义,否则 kompose 会失败。
重启 如果你想创建没有控制器的普通 Pod,可以使用 docker-compose 的 restart
结构来指定这一行为。请参考下表了解 restart 的不同参数。
docker-compose restart创建的对象 Pod restartPolicy ""控制器对象 Alwaysalways控制器对象 Alwayson-failurePod OnFailurenoPod Never
说明: 控制器对象可以是 deployment 或 replicationcontroller 等。
例如,pival Service 将在这里变成 Pod。这个容器计算 pi 的取值。
version : '2'
services :
pival :
image : perl
command : ["perl" , "-Mbignum=bpi" , "-wle" , "print bpi(2000)" ]
restart : "on-failure"
关于 Deployment Config 的提醒 如果 Docker Compose 文件中为服务声明了卷,Deployment (Kubernetes) 或
DeploymentConfig (OpenShift) 策略会从 "RollingUpdate" (默认) 变为 "Recreate"。
这样做的目的是为了避免服务的多个实例同时访问卷。
如果 Docker Compose 文件中的服务名包含 _(例如 web_service),
那么将会被替换为 -,服务也相应的会重命名(例如 web-service)。
Kompose 这样做的原因是 "Kubernetes" 不允许对象名称中包含 _。
请注意,更改服务名称可能会破坏一些 docker-compose 文件。
Docker Compose 版本 Kompose 支持的 Docker Compose 版本包括:1、2 和 3。
对 2.1 和 3.2 版本的支持还有限,因为它们还在实验阶段。
所有三个版本的兼容性列表请查看我们的
转换文档 ,
文档中列出了所有不兼容的 Docker Compose 关键字。
4.4 - 管理 Kubernetes 对象 用声明式和命令式范型与 Kubernetes API 交互。
4.4.1 - 使用配置文件对 Kubernetes 对象进行声明式管理 你可以通过在一个目录中存储多个对象配置文件、并使用 kubectl apply
来递归地创建和更新对象来创建、更新和删除 Kubernetes 对象。
这种方法会保留对现有对象已作出的修改,而不会将这些更改写回到对象配置文件中。
kubectl diff 也会给你呈现 apply 将作出的变更的预览。
准备开始 安装 kubectl 。
你必须拥有一个 Kubernetes 的集群,同时你的 Kubernetes 集群必须带有 kubectl 命令行工具。
如果你还没有集群,你可以通过 Minikube 构建一
个你自己的集群,或者你可以使用下面任意一个 Kubernetes 工具构建:
要获知版本信息,请输入
kubectl version.
权衡取舍 kubectl 工具能够支持三种对象管理方式:
关于每种对象管理的优缺点的讨论,可参见
Kubernetes 对象管理 。
概览 声明式对象管理需要用户对 Kubernetes 对象定义和配置有比较深刻的理解。
如果你还没有这方面的知识储备,请先阅读下面的文档:
以下是本文档中使用的术语的定义:
对象配置文件/配置文件 :一个定义 Kubernetes 对象的配置的文件。
本主题展示如何将配置文件传递给 kubectl apply。
配置文件通常存储于类似 Git 这种源码控制系统中。现时对象配置/现时配置 :由 Kubernetes 集群所观测到的对象的现时配置值。
这些配置保存在 Kubernetes 集群存储(通常是 etcd)中。声明式配置写者/声明式写者 :负责更新现时对象的人或者软件组件。
本主题中的声明式写者负责改变对象配置文件并执行 kubectl apply 命令
以写入变更。如何创建对象 使用 kubectl apply 来创建指定目录中配置文件所定义的所有对象,除非对应对象已经存在:
此操作会在每个对象上设置 kubectl.kubernetes.io/last-applied-configuration: '{...}'
注解。注解值中包含了用来创建对象的配置文件的内容。
说明: 添加 -R 标志可以递归地处理目录。
下面是一个对象配置文件示例:
apiVersion : apps/v1
kind : Deployment
metadata :
name : nginx-deployment
spec :
selector :
matchLabels :
app : nginx
minReadySeconds : 5
template :
metadata :
labels :
app : nginx
spec :
containers :
- name : nginx
image : nginx:1.14.2
ports :
- containerPort : 80
执行 kubectl diff 可以打印出将被创建的对象:
kubectl diff -f https://k8s.io/examples/application/simple_deployment.yaml
使用 kubectl apply 来创建对象:
kubectl apply -f https://k8s.io/examples/application/simple_deployment.yaml
使用 kubectl get 打印其现时配置:
kubectl get -f https://k8s.io/examples/application/simple_deployment.yaml -o yaml
输出显示注解 kubectl.kubernetes.io/last-applied-configuration 被写入到
现时配置中,并且其内容与配置文件相同:
kind : Deployment
metadata :
annotations :
# ...
# This is the json representation of simple_deployment.yaml
# It was written by kubectl apply when the object was created
kubectl.kubernetes.io/last-applied-configuration : |
{"apiVersion":"apps/v1","kind":"Deployment",
"metadata":{"annotations":{},"name":"nginx-deployment","namespace":"default"},
"spec":{"minReadySeconds":5,"selector":{"matchLabels":{"app":nginx}},"template":{"metadata":{"labels":{"app":"nginx"}},
"spec":{"containers":[{"image":"nginx:1.14.2","name":"nginx",
"ports":[{"containerPort":80}]}]}}}}
# ...
spec :
# ...
minReadySeconds : 5
selector :
matchLabels :
# ...
app : nginx
template :
metadata :
# ...
labels :
app : nginx
spec :
containers :
- image : nginx:1.14.2
# ...
name : nginx
ports :
- containerPort : 80
# ...
# ...
# ...
# ...
如何更新对象 你也可以使用 kubectl apply 来更新某个目录中定义的所有对象,即使那些对象已经存在。
这一操作会隐含以下行为:
在现时配置中设置配置文件中出现的字段; 在现时配置中清除配置文件中已删除的字段。 kubectl diff -f <目录>/
kubectl apply -f <目录>/
说明: 使用 -R 标志递归处理目录。
下面是一个配置文件示例:
apiVersion : apps/v1
kind : Deployment
metadata :
name : nginx-deployment
spec :
selector :
matchLabels :
app : nginx
minReadySeconds : 5
template :
metadata :
labels :
app : nginx
spec :
containers :
- name : nginx
image : nginx:1.14.2
ports :
- containerPort : 80
使用 kubectl apply 来创建对象:
kubectl apply -f https://k8s.io/examples/application/simple_deployment.yaml
说明: 出于演示的目的,上面的命令引用的是单个文件而不是整个目录。
使用 kubectl get 打印现时配置:
kubectl get -f https://k8s.io/examples/application/simple_deployment.yaml -o yaml
输出显示,注解 kubectl.kubernetes.io/last-applied-configuration 被写入到
现时配置中,并且其取值与配置文件内容相同。
kind : Deployment
metadata :
annotations :
# ...
# 此为 simple_deployment.yaml 的 JSON 表示
# 在对象创建时由 kubectl apply 命令写入
kubectl.kubernetes.io/last-applied-configuration : |
{"apiVersion":"apps/v1","kind":"Deployment",
"metadata":{"annotations":{},"name":"nginx-deployment","namespace":"default"},
"spec":{"minReadySeconds":5,"selector":{"matchLabels":{"app":nginx}},"template":{"metadata":{"labels":{"app":"nginx"}},
"spec":{"containers":[{"image":"nginx:1.14.2","name":"nginx",
"ports":[{"containerPort":80}]}]}}}}
# ...
spec :
# ...
minReadySeconds : 5
selector :
matchLabels :
# ...
app : nginx
template :
metadata :
# ...
labels :
app : nginx
spec :
containers :
- image : nginx:1.14.2
# ...
name : nginx
ports :
- containerPort : 80
# ...
# ...
# ...
# ...
通过 kubeclt scale 命令直接更新现时配置中的 replicas 字段。
这一命令没有使用 kubectl apply:
kubectl scale deployment/nginx-deployment --replicas= 2
使用 kubectl get 来打印现时配置:
kubectl get deployment nginx-deployment -o yaml
输出显示,replicas 字段已经被设置为 2,而 last-applied-configuration 注解中
并不包含 replicas 字段。
apiVersion : apps/v1
kind : Deployment
metadata :
annotations :
# ...
# 注意注解中并不包含 replicas
# 这是因为更新并不是通过 kubectl apply 来执行的
kubectl.kubernetes.io/last-applied-configuration : |
{"apiVersion":"apps/v1","kind":"Deployment",
"metadata":{"annotations":{},"name":"nginx-deployment","namespace":"default"},
"spec":{"minReadySeconds":5,"selector":{"matchLabels":{"app":nginx}},"template":{"metadata":{"labels":{"app":"nginx"}},
"spec":{"containers":[{"image":"nginx:1.14.2","name":"nginx",
"ports":[{"containerPort":80}]}]}}}}
# ...
spec :
replicas : 2 # written by scale
# ...
minReadySeconds : 5
selector :
matchLabels :
# ...
app : nginx
template :
metadata :
# ...
labels :
app : nginx
spec :
containers :
- image : nginx:1.14.2
# ...
name : nginx
ports :
- containerPort : 80
# ...
现在更新 simple_deployment.yaml 配置文件,将镜像文件从
nginx:1.14.2 更改为 nginx:1.16.1,同时删除minReadySeconds 字段:
apiVersion : apps/v1
kind : Deployment
metadata :
name : nginx-deployment
spec :
selector :
matchLabels :
app : nginx
template :
metadata :
labels :
app : nginx
spec :
containers :
- name : nginx
image : nginx:1.16.1 # update the image
ports :
- containerPort : 80
应用对配置文件所作更改:
kubectl diff -f https://k8s.io/examples/application/update_deployment.yaml
kubectl apply -f https://k8s.io/examples/application/update_deployment.yaml
使用 kubectl get 打印现时配置:
kubectl get -f https://k8s.io/examples/application/update_deployment.yaml -o yaml
输出显示现时配置中发生了以下更改:
字段 replicas 保留了 kubectl scale 命令所设置的值:2;
之所以该字段被保留是因为配置文件中并没有设置 replicas。 字段 image 的内容已经从 nginx:1.14.2 更改为 nginx:1.16.1。 注解 last-applied-configuration 内容被更改为新的镜像名称。 字段 minReadySeconds 被移除。 注解 last-applied-configuration 中不再包含 minReadySeconds 字段。 apiVersion : apps/v1
kind : Deployment
metadata :
annotations :
# ...
# 注解中包含更新后的镜像 nginx 1.16.1
# 但是其中并不包含更改后的 replicas 值 2
kubectl.kubernetes.io/last-applied-configuration : |
{"apiVersion":"apps/v1","kind":"Deployment",
"metadata":{"annotations":{},"name":"nginx-deployment","namespace":"default"},
"spec":{"selector":{"matchLabels":{"app":nginx}},"template":{"metadata":{"labels":{"app":"nginx"}},
"spec":{"containers":[{"image":"nginx:1.16.1","name":"nginx",
"ports":[{"containerPort":80}]}]}}}}
# ...
spec :
replicas : 2 # 由 `kubectl scale` 设置,被 `kubectl apply` 命令忽略
# minReadySeconds 被 `kubectl apply` 清除
# ...
selector :
matchLabels :
# ...
app : nginx
template :
metadata :
# ...
labels :
app : nginx
spec :
containers :
- image : nginx:1.16.1 # 由 `kubectl apply` 设置
# ...
name : nginx
ports :
- containerPort : 80
# ...
# ...
# ...
# ...
警告: 将 kubectl apply 与指令式对象配置命令 kubectl create 或 kubectl replace
混合使用是不受支持的。这是因为 create 和 replace 命令都不会保留
kubectl apply 用来计算更新内容所使用的
kubectl.kubernetes.io/last-applied-configuration 注解值。
如何删除对象 有两种方法来删除 kubectl apply 管理的对象。
建议操作:kubectl delete -f <文件名> 使用指令式命令来手动删除对象是建议的方法,因为这种方法更为明确地给出了
要删除的内容是什么,且不容易造成用户不小心删除了其他对象的情况。
替代方式:kubectl apply -f <目录名称/> --prune -l your=label 只有在充分理解此命令背后含义的情况下才建议这样操作。
警告: kubectl apply --prune 命令本身仍处于 Alpha 状态,在后续发布版本中可能会
引入一些向后不兼容的变化。
警告: 在使用此命令时必须小心,这样才不会无意中删除不想删除的对象。
作为 kubectl delete 操作的替代方式,你可以在目录中对象配置文件被删除之后,
使用 kubectl apply 来辩识要删除的对象。
带 --prune 标志的 apply 命令会首先查询 API 服务器,获得与某组标签相匹配
的对象列表,之后将返回的现时对象配置与目录中的对象配置文件相比较。
如果某对象在查询中被匹配到,但在目录中没有文件与其相对应,并且其中还包含
last-applied-configuration 注解,则该对象会被删除。
kubectl apply -f <directory/> --prune -l <labels>
警告: 带剪裁(prune)行为的 apply 操作应在包含对象配置文件的目录的根目录运行。
如果在其子目录中运行,可能导致对象被不小心删除。
因为某些对象可能与 -l <标签> 的标签选择算符匹配,但其配置文件不在当前
子目录下。
如何查看对象 你可以使用 kubectl get 并指定 -o yaml 选项来查看现时对象的配置:
kubectl get -f <文件名 | URL> -o yaml
apply 操作是如何计算配置差异并合并变更的? 注意: patch 是一种更新操作,其作用域为对象的一些特定字段而不是整个对象。
这使得你可以更新对象的特定字段集合而不必先要读回对象。
kubectl apply 更新对象的现时配置,它是通过向 API 服务器发送一个 patch 请求
来执行更新动作的。
所提交的补丁中定义了对现时对象配置中特定字段的更新。
kubectl apply 命令会使用当前的配置文件、现时配置以及现时配置中保存的
last-applied-configuration 注解内容来计算补丁更新内容。
合并补丁计算 kubectl apply 命令将配置文件的内容写入到
kubectl.kubernetes.io/last-applied-configuration 注解中。
这些内容用来识别配置文件中已经移除的、因而也需要从现时配置中删除的字段。
用来计算要删除或设置哪些字段的步骤如下:
计算要删除的字段,即在 last-applied-configuration 中存在但在
配置文件中不再存在的字段。 计算要添加或设置的字段,即在配置文件中存在但其取值与现时配置不同的字段。 下面是一个例子。假定此文件是某 Deployment 对象的配置文件:
apiVersion : apps/v1
kind : Deployment
metadata :
name : nginx-deployment
spec :
selector :
matchLabels :
app : nginx
template :
metadata :
labels :
app : nginx
spec :
containers :
- name : nginx
image : nginx:1.16.1 # update the image
ports :
- containerPort : 80
同时假定同一 Deployment 对象的现时配置如下:
apiVersion : apps/v1
kind : Deployment
metadata :
annotations :
# ...
kubectl.kubernetes.io/last-applied-configuration : |
{"apiVersion":"apps/v1","kind":"Deployment",
"metadata":{"annotations":{},"name":"nginx-deployment","namespace":"default"},
"spec":{"minReadySeconds":5,"selector":{"matchLabels":{"app":nginx}},"template":{"metadata":{"labels":{"app":"nginx"}},
"spec":{"containers":[{"image":"nginx:1.14.2","name":"nginx",
"ports":[{"containerPort":80}]}]}}}}
# ...
spec :
replicas : 2
# ...
minReadySeconds : 5
selector :
matchLabels :
# ...
app : nginx
template :
metadata :
# ...
labels :
app : nginx
spec :
containers :
- image : nginx:1.14.2
# ...
name : nginx
ports :
- containerPort : 80
# ...
下面是 kubectl apply 将执行的合并计算:
通过读取 last-applied-configuration 并将其与配置文件中的值相比较,
计算要删除的字段。
对于本地对象配置文件中显式设置为空的字段,清除其在现时配置中的设置,
无论这些字段是否出现在 last-applied-configuration 中。
在此例中,minReadySeconds 出现在 last-applied-configuration 注解中,但
并不存在于配置文件中。
动作: 从现时配置中删除 minReadySeconds 字段。 通过读取配置文件中的值并将其与现时配置相比较,计算要设置的字段。
在这个例子中,配置文件中的 image 值与现时配置中的 image 不匹配。
动作 :设置现时配置中的 image 值。 设置 last-applied-configuration 注解的内容,使之与配置文件匹配。 将第 1、2、3 步骤得出的结果合并,构成向 API 服务器发送的补丁请求内容。 下面是此合并操作之后形成的现时配置:
apiVersion : apps/v1
kind : Deployment
metadata :
annotations :
# ...
# 注解中包含更新后的 image,nginx 1.11.9,
# 但不包含更新后的 replicas
kubectl.kubernetes.io/last-applied-configuration : |
{"apiVersion":"apps/v1","kind":"Deployment",
"metadata":{"annotations":{},"name":"nginx-deployment","namespace":"default"},
"spec":{"selector":{"matchLabels":{"app":nginx}},"template":{"metadata":{"labels":{"app":"nginx"}},
"spec":{"containers":[{"image":"nginx:1.16.1","name":"nginx",
"ports":[{"containerPort":80}]}]}}}}
# ...
spec :
selector :
matchLabels :
# ...
app : nginx
replicas : 2
# minReadySeconds 此字段被清除
# ...
template :
metadata :
# ...
labels :
app : nginx
spec :
containers :
- image : nginx:1.16.1
# ...
name : nginx
ports :
- containerPort : 80
# ...
# ...
# ...
# ...
不同类型字段的合并方式 配置文件中的特定字段与现时配置合并时,合并方式取决于字段类型。
字段类型有几种:
基本类型 :字段类型为 string、integer 或 boolean 之一。
例如:image 和 replicas 字段都是基本类型字段。
动作: 替换。
map :也称作 object 。类型为 map 或包含子域的复杂结构。例如,labels、
annotations、spec 和 metadata 都是 map。
动作: 合并元素或子字段。
list :包含元素列表的字段,其中每个元素可以是基本类型或 map。
例如,containers、ports 和 args 都是 list。
动作: 不一定。
当 kubectl apply 更新某个 map 或 list 字段时,它通常不会替换整个字段,而是会
更新其中的各个子元素。例如,当合并 Deployment 的 spec 时,kubectl 并不会
将其整个替换掉。相反,实际操作会是对 replicas 这类 spec
的子字段来执行比较和更新。
合并对基本类型字段的更新 基本类型字段会被替换或清除。
说明: - 表示的是“不适用”,因为指定数值未被使用。
字段在对象配置文件中 字段在现时对象配置中 字段在 last-applied-configuration 中 动作 是 是 - 将配置文件中值设置到现时配置上。 是 否 - 将配置文件中值设置到现时配置上。 否 - 是 从现时配置中移除。 否 - 否 什么也不做。保持现时值。
合并对 map 字段的变更 用来表示映射的字段在合并时会逐个子字段或元素地比较:
说明: - 表示的是“不适用”,因为指定数值未被使用。
键存在于对象配置文件中 键存在于现时对象配置中 键存在于 last-applied-configuration 中 动作 是 是 - 比较子域取值。 是 否 - 将现时配置设置为本地配置值。 否 - 是 从现时配置中删除键。 否 - 否 什么也不做,保留现时值。
合并 list 类型字段的变更 对 list 类型字段的变更合并会使用以下三种策略之一:
如果 list 所有元素都是基本类型则替换整个 list。 如果 list 中元素是复合结构则逐个元素执行合并操作。 合并基本类型元素构成的 list。 策略的选择是基于各个字段做出的。
如果 list 中元素都是基本类型则替换整个 list 将整个 list 视为一个基本类型字段。或者整个替换或者整个删除。
此操作会保持 list 中元素顺序不变
示例: 使用 kubectl apply 来更新 Pod 中 Container 的 args 字段。此操作会
将现时配置中的 args 值设为配置文件中的值。
所有之前添加到现时配置中的 args 元素都会丢失。
配置文件中的 args 元素的顺序在被添加到现时配置中时保持不变。
# last-applied-configuration 值
args : ["a" , "b" ]
# 配置文件值
args : ["a" , "c" ]
# 现时配置
args : ["a" , "b" , "d" ]
# 合并结果
args : ["a" , "c" ]
解释: 合并操作将配置文件中的值当做新的 list 值。
如果 list 中元素为复合类型则逐个执行合并 此操作将 list 视为 map,并将每个元素中的特定字段当做其主键。
逐个元素地执行添加、删除或更新操作。结果顺序无法得到保证。
此合并策略会使用每个字段上的一个名为 patchMergeKey 的特殊标签。
Kubernetes 源代码中为每个字段定义了 patchMergeKey:
types.go
当合并由 map 组成的 list 时,给定元素中被设置为 patchMergeKey 的字段会被
当做该元素的 map 键值来使用。
例如: 使用 kubectl apply 来更新 Pod 规约中的 containers 字段。
此操作会将 containers 列表视作一个映射来执行合并,每个元素的主键为 name。
# last-applied-configuration 值
containers :
- name : nginx
image : nginx:1.16
- name : nginx-helper-a # 键 nginx-helper-a 会被删除
image : helper:1.3
- name : nginx-helper-b # 键 nginx-helper-b 会被保留
image : helper:1.3
# 配置文件值
containers :
- name : nginx
image : nginx:1.16
- name : nginx-helper-b
image : helper:1.3
- name : nginx-helper-c # 键 nginx-helper-c 会被添加
image : helper:1.3
# 现时配置
containers :
- name : nginx
image : nginx:1.16
- name : nginx-helper-a
image : helper:1.3
- name : nginx-helper-b
image : helper:1.3
args : ["run" ] # 字段会被保留
- name : nginx-helper-d # 键 nginx-helper-d 会被保留
image : helper:1.3
# 合并结果
containers :
- name : nginx
image : nginx:1.16
# 元素 nginx-helper-a 被删除
- name : nginx-helper-b
image : helper:1.3
args : ["run" ] # 字段被保留
- name : nginx-helper-c # 新增元素
image : helper:1.3
- name : nginx-helper-d # 此元素被忽略(保留)
image : helper:1.3
解释:
名为 "nginx-helper-a" 的容器被删除,因为配置文件中不存在同名的容器。 名为 "nginx-helper-b" 的容器的现时配置中的 args 被保留。
kubectl apply 能够辩识出现时配置中的容器 "nginx-helper-b" 与配置文件
中的容器 "nginx-helper-b" 相同,即使它们的字段值有些不同(配置文件中未给定
args 值)。这是因为 patchMergeKey 字段(name)的值在两个版本中都一样。 名为 "nginx-helper-c" 的容器是新增的,因为在配置文件中的这个容器尚不存在
于现时配置中。 名为 "nginx-helper-d" 的容器被保留下来,因为在 last-applied-configuration
中没有与之同名的元素。 合并基本类型元素 list 在 Kubernetes 1.5 中,尚不支持对由基本类型元素构成的 list 进行合并。
说明: 选择上述哪种策略是由源码中给定字段的
patchStrategy 标记来控制的:
types.go
如果 list 类型字段未设置
patchStrategy,则整个 list 会被替换掉。
默认字段值 API 服务器会在对象创建时其中某些字段未设置的情况下在现时配置中为其设置默认值。
下面是一个 Deployment 的配置文件。文件未设置 strategy:
apiVersion : apps/v1
kind : Deployment
metadata :
name : nginx-deployment
spec :
selector :
matchLabels :
app : nginx
minReadySeconds : 5
template :
metadata :
labels :
app : nginx
spec :
containers :
- name : nginx
image : nginx:1.14.2
ports :
- containerPort : 80
使用 kubectl apply 创建对象:
kubectl apply -f https://k8s.io/examples/application/simple_deployment.yaml
使用 kubectl get 打印现时配置:
kubectl get -f https://k8s.io/examples/application/simple_deployment.yaml -o yaml
输出显示 API 在现时配置中为某些字段设置了默认值。
这些字段在配置文件中并未设置。
apiVersion : apps/v1
kind : Deployment
# ...
spec :
selector :
matchLabels :
app : nginx
minReadySeconds : 5
replicas : 1 # API 服务器所设默认值
strategy :
rollingUpdate : # API 服务器基于 strategy.type 所设默认值
maxSurge : 1
maxUnavailable : 1
type : RollingUpdate # API 服务器所设默认值
template :
metadata :
creationTimestamp : null
labels :
app : nginx
spec :
containers :
- image : nginx:1.14.2
imagePullPolicy : IfNotPresent # API 服务器所设默认值
name : nginx
ports :
- containerPort : 80
protocol : TCP # API 服务器所设默认值
resources : {} # API 服务器所设默认值
terminationMessagePath : /dev/termination-log # API 服务器所设默认值
dnsPolicy : ClusterFirst # API 服务器所设默认值
restartPolicy : Always # API 服务器所设默认值
securityContext : {} # API 服务器所设默认值
terminationGracePeriodSeconds : 30 # API 服务器所设默认值
# ...
在补丁请求中,已经设置了默认值的字段不会被重新设回其默认值,除非
在补丁请求中显式地要求清除。对于默认值取决于其他字段的某些字段而言,
这可能会引发一些意想不到的行为。当所依赖的其他字段后来发生改变时,
基于它们所设置的默认值只能在显式执行清除操作时才会被更新。
为此,建议在配置文件中为服务器设置默认值的字段显式提供定义,即使所
给的定义与服务器端默认值设定相同。这样可以使得辩识无法被服务器重新
基于默认值来设置的冲突字段变得容易。
示例:
# last-applied-configuration
spec :
template :
metadata :
labels :
app : nginx
spec :
containers :
- name : nginx
image : nginx:1.14.2
ports :
- containerPort : 80
# 配置文件
spec :
strategy :
type : Recreate # 更新的值
template :
metadata :
labels :
app : nginx
spec :
containers :
- name : nginx
image : nginx:1.14.2
ports :
- containerPort : 80
# 现时配置
spec :
strategy :
type : RollingUpdate # 默认设置的值
rollingUpdate : # 基于 type 设置的默认值
maxSurge : 1
maxUnavailable : 1
template :
metadata :
labels :
app : nginx
spec :
containers :
- name : nginx
image : nginx:1.14.2
ports :
- containerPort : 80
# 合并后的结果 - 出错!
spec :
strategy :
type : Recreate # 更新的值:与 rollingUpdate 不兼容
rollingUpdate : # 默认设置的值:与 "type: Recreate" 冲突
maxSurge : 1
maxUnavailable : 1
template :
metadata :
labels :
app : nginx
spec :
containers :
- name : nginx
image : nginx:1.14.2
ports :
- containerPort : 80
解释:
用户创建 Deployment,未设置 strategy.type。 服务器为 strategy.type 设置默认值 RollingUpdate,并为 strategy.rollingUpdate
设置默认值。 用户改变 strategy.type 为 Recreate。字段 strategy.rollingUpdate 仍会取其
默认设置值,尽管服务器期望该字段被清除。
如果 strategy.rollingUpdate 值最初于配置文件中定义,则它们需要被清除
这一点就更明确一些。 apply 操作失败,因为 strategy.rollingUpdate 未被清除。
strategy.rollingupdate 在 strategy.type 为 Recreate 不可被设定。建议:以下字段应该在对象配置文件中显式定义:
如 Deployment、StatefulSet、Job、DaemonSet、ReplicaSet 和 ReplicationController
这类负载的选择算符和 PodTemplate 标签 Deployment 的上线策略 如何清除服务器端按默认值设置的字段或者被其他写者设置的字段 没有出现在配置文件中的字段可以通过将其值设置为 null 并应用配置文件来清除。
对于由服务器按默认值设置的字段,清除操作会触发重新为字段设置新的默认值。
如何将字段的属主在配置文件和直接指令式写者之间切换 更改某个对象字段时,应该采用下面的方法:
使用 kubectl apply. 直接写入到现时配置,但不更改配置文件本身,例如使用 kubectl scale。 将属主从直接指令式写者更改为配置文件 将字段添加到配置文件。针对该字段,不再直接执行对现时配置的修改。
修改均通过 kubectl apply 来执行。
将属主从配置文件改为直接指令式写者 在 Kubernetes 1.5 中,将字段的属主从配置文件切换到某指令式写者需要手动
执行以下步骤:
从配置文件中删除该字段; 将字段从现时对象的 kubectl.kubernetes.io/last-applied-configuration 注解
中删除。 更改管理方法 Kubernetes 对象在同一时刻应该只用一种方法来管理。
从一种方法切换到另一种方法是可能的,但这一切换是一个手动过程。
说明: 在声明式管理方法中使用指令式命令来删除对象是可以的。
从指令式命令管理切换到声明式对象配置 从指令式命令管理切换到声明式对象配置管理的切换包含以下几个手动步骤:
将现时对象导出到本地配置文件:
kubectl get <kind>/<name> -o yaml > <kind>_<name>.yaml
手动移除配置文件中的 status 字段。
说明: 这一步骤是可选的,因为 kubectl apply 并不会更新 status 字段,即便
配置文件中包含 status 字段。
设置对象上的 kubectl.kubernetes.io/last-applied-configuration 注解:
kubectl replace --save-config -f <kind>_<name>.yaml
更改过程,使用 kubectl apply 专门管理对象。
从指令式对象配置切换到声明式对象配置 在对象上设置 kubectl.kubernetes.io/last-applied-configuration 注解:
kubectl replace -save-config -f <kind>_<name>.yaml
自此排他性地使用 kubectl apply 来管理对象。
定义控制器选择算符和 PodTemplate 标签 警告: 强烈不建议更改控制器上的选择算符。
建议的方法是定义一个不可变更的 PodTemplate 标签,仅用于控制器选择算符且
不包含其他语义性的含义。
示例:
selector :
matchLabels :
controller-selector : "apps/v1/deployment/nginx"
template :
metadata :
labels :
controller-selector : "apps/v1/deployment/nginx"
接下来 4.4.2 - 使用 Kustomize 对 Kubernetes 对象进行声明式管理 Kustomize 是一个独立的工具,用来通过
kustomization 文件
定制 Kubernetes 对象。
从 1.14 版本开始,kubectl 也开始支持使用 kustomization 文件来管理 Kubernetes 对象。
要查看包含 kustomization 文件的目录中的资源,执行下面的命令:
kubectl kustomize <kustomization_directory>
要应用这些资源,使用参数 --kustomize 或 -k 标志来执行 kubectl apply:
kubectl apply -k <kustomization_directory>
准备开始 安装 kubectl .
你必须拥有一个 Kubernetes 的集群,同时你的 Kubernetes 集群必须带有 kubectl 命令行工具。
如果你还没有集群,你可以通过 Minikube 构建一
个你自己的集群,或者你可以使用下面任意一个 Kubernetes 工具构建:
要获知版本信息,请输入
kubectl version.
Kustomize 概述 Kustomize 是一个用来定制 Kubernetes 配置的工具。它提供以下功能特性来管理
应用配置文件:
从其他来源生成资源 为资源设置贯穿性(Cross-Cutting)字段 组织和定制资源集合 生成资源 ConfigMap 和 Secret 包含其他 Kubernetes 对象(如 Pod)所需要的配置或敏感数据。
ConfigMap 或 Secret 中数据的来源往往是集群外部,例如某个 .properties
文件或者 SSH 密钥文件。
Kustomize 提供 secretGenerator 和 configMapGenerator,可以基于文件或字面
值来生成 Secret 和 ConfigMap。
configMapGenerator 要基于文件来生成 ConfigMap,可以在 configMapGenerator 的 files
列表中添加表项。
下面是一个根据 .properties 文件中的数据条目来生成 ConfigMap 的示例:
# 生成一个 application.properties 文件
cat <<EOF >application.properties
FOO=Bar
EOF
cat <<EOF >./kustomization.yaml
configMapGenerator:
- name: example-configmap-1
files:
- application.properties
EOF
所生成的 ConfigMap 可以使用下面的命令来检查:
所生成的 ConfigMap 为:
apiVersion : v1
data :
application.properties : |
FOO=Bar
kind : ConfigMap
metadata :
name : example-configmap-1-8mbdf7882g
ConfigMap 也可基于字面的键值偶对来生成。要基于键值偶对来生成 ConfigMap,
在 configMapGenerator 的 literals 列表中添加表项。下面是一个例子,展示
如何使用键值偶对中的数据条目来生成 ConfigMap 对象:
cat <<EOF >./kustomization.yaml
configMapGenerator:
- name: example-configmap-2
literals:
- FOO=Bar
EOF
可以用下面的命令检查所生成的 ConfigMap:
所生成的 ConfigMap 为:
apiVersion : v1
data :
FOO : Bar
kind : ConfigMap
metadata :
name : example-configmap-2-g2hdhfc6tk
secretGenerator 你可以基于文件或者键值偶对来生成 Secret。要使用文件内容来生成 Secret,
在 secretGenerator 下面的 files 列表中添加表项。
下面是一个根据文件中数据来生成 Secret 对象的示例:
# 创建一个 password.txt 文件
cat <<EOF >./password.txt
username=admin
password=secret
EOF
cat <<EOF >./kustomization.yaml
secretGenerator:
- name: example-secret-1
files:
- password.txt
EOF
所生成的 Secret 如下:
apiVersion : v1
data :
password.txt : dXNlcm5hbWU9YWRtaW4KcGFzc3dvcmQ9c2VjcmV0Cg==
kind : Secret
metadata :
name : example-secret-1-t2kt65hgtb
type : Opaque
要基于键值偶对字面值生成 Secret,先要在 secretGenerator 的 literals
列表中添加表项。下面是基于键值偶对中数据条目来生成 Secret 的示例:
cat <<EOF >./kustomization.yaml
secretGenerator:
- name: example-secret-2
literals:
- username=admin
- password=secret
EOF
所生成的 Secret 如下:
apiVersion : v1
data :
password : c2VjcmV0
username : YWRtaW4=
kind : Secret
metadata :
name : example-secret-2-t52t6g96d8
type : Opaque
generatorOptions 所生成的 ConfigMap 和 Secret 都会包含内容哈希值后缀。
这是为了确保内容发生变化时,所生成的是新的 ConfigMap 或 Secret。
要禁止自动添加后缀的行为,用户可以使用 generatorOptions。
除此以外,为生成的 ConfigMap 和 Secret 指定贯穿性选项也是可以的。
cat <<EOF >./kustomization.yaml
configMapGenerator:
- name: example-configmap-3
literals:
- FOO=Bar
generatorOptions:
disableNameSuffixHash: true
labels:
type: generated
annotations:
note: generated
EOF
运行 kubectl kustomize ./ 来查看所生成的 ConfigMap:
apiVersion : v1
data :
FOO : Bar
kind : ConfigMap
metadata :
annotations :
note : generated
labels :
type : generated
name : example-configmap-3
设置贯穿性字段 在项目中为所有 Kubernetes 对象设置贯穿性字段是一种常见操作。
贯穿性字段的一些使用场景如下:
为所有资源设置相同的名字空间 为所有对象添加相同的前缀或后缀 为对象添加相同的标签集合 为对象添加相同的注解集合 下面是一个例子:
# 创建一个 deployment.yaml
cat <<EOF >./deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx
spec:
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
EOF
cat <<EOF >./kustomization.yaml
namespace: my-namespace
namePrefix: dev-
nameSuffix: "-001"
commonLabels:
app: bingo
commonAnnotations:
oncallPager: 800-555-1212
resources:
- deployment.yaml
EOF
执行 kubectl kustomize ./ 查看这些字段都被设置到 Deployment 资源上:
apiVersion : apps/v1
kind : Deployment
metadata :
annotations :
oncallPager : 800-555-1212
labels :
app : bingo
name : dev-nginx-deployment-001
namespace : my-namespace
spec :
selector :
matchLabels :
app : bingo
template :
metadata :
annotations :
oncallPager : 800-555-1212
labels :
app : bingo
spec :
containers :
- image : nginx
name : nginx
组织和定制资源 一种常见的做法是在项目中构造资源集合并将其放到同一个文件或目录中管理。
Kustomize 提供基于不同文件来组织资源并向其应用补丁或者其他定制的能力。
组织 Kustomize 支持组合不同的资源。kustomization.yaml 文件的 resources 字段
定义配置中要包含的资源列表。你可以将 resources 列表中的路径设置为资源配置文件
的路径。下面是由 Deployment 和 Service 构成的 NGINX 应用的示例:
# 创建 deployment.yaml 文件
cat <<EOF > deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-nginx
spec:
selector:
matchLabels:
run: my-nginx
replicas: 2
template:
metadata:
labels:
run: my-nginx
spec:
containers:
- name: my-nginx
image: nginx
ports:
- containerPort: 80
EOF
# 创建 service.yaml 文件
cat <<EOF > service.yaml
apiVersion: v1
kind: Service
metadata:
name: my-nginx
labels:
run: my-nginx
spec:
ports:
- port: 80
protocol: TCP
selector:
run: my-nginx
EOF
# 创建 kustomization.yaml 来组织以上两个资源
cat <<EOF >./kustomization.yaml
resources:
- deployment.yaml
- service.yaml
EOF
kubectl kustomize ./ 所得到的资源中既包含 Deployment 也包含 Service 对象。
定制 补丁文件(Patches)可以用来对资源执行不同的定制。
Kustomize 通过 patchesStrategicMerge 和 patchesJson6902 支持不同的打补丁
机制。patchesStrategicMerge 的内容是一个文件路径的列表,其中每个文件都应可解析为
策略性合并补丁(Strategic Merge Patch) 。
补丁文件中的名称必须与已经加载的资源的名称匹配。
建议构造规模较小的、仅做一件事情的补丁。
例如,构造一个补丁来增加 Deployment
的副本个数;构造另外一个补丁来设置内存限制。
# 创建 deployment.yaml 文件
cat <<EOF > deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-nginx
spec:
selector:
matchLabels:
run: my-nginx
replicas: 2
template:
metadata:
labels:
run: my-nginx
spec:
containers:
- name: my-nginx
image: nginx
ports:
- containerPort: 80
EOF
# 生成一个补丁 increase_replicas.yaml
cat <<EOF > increase_replicas.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-nginx
spec:
replicas: 3
EOF
# 生成另一个补丁 set_memory.yaml
cat <<EOF > set_memory.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-nginx
spec:
template:
spec:
containers:
- name: my-nginx
resources:
limits:
memory: 512Mi
EOF
cat <<EOF >./kustomization.yaml
resources:
- deployment.yaml
patchesStrategicMerge:
- increase_replicas.yaml
- set_memory.yaml
EOF
执行 kubectl kustomize ./ 来查看 Deployment:
apiVersion : apps/v1
kind : Deployment
metadata :
name : my-nginx
spec :
replicas : 3
selector :
matchLabels :
run : my-nginx
template :
metadata :
labels :
run : my-nginx
spec :
containers :
- image : nginx
name : my-nginx
ports :
- containerPort : 80
resources :
limits :
memory : 512Mi
并非所有资源或者字段都支持策略性合并补丁。为了支持对任何资源的任何字段进行修改,
Kustomize 提供通过 patchesJson6902 来应用 JSON 补丁
的能力。为了给 JSON 补丁找到正确的资源,需要在 kustomization.yaml 文件中指定资源的
组(group)、版本(version)、类别(kind)和名称(name)。
例如,为某 Deployment 对象增加副本个数的操作也可以通过 patchesJson6902
来完成:
# 创建一个 deployment.yaml 文件
cat <<EOF > deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-nginx
spec:
selector:
matchLabels:
run: my-nginx
replicas: 2
template:
metadata:
labels:
run: my-nginx
spec:
containers:
- name: my-nginx
image: nginx
ports:
- containerPort: 80
EOF
# 创建一个 JSON 补丁文件
cat <<EOF > patch.yaml
- op: replace
path: /spec/replicas
value: 3
EOF
# 创建一个 kustomization.yaml
cat <<EOF >./kustomization.yaml
resources:
- deployment.yaml
patchesJson6902:
- target:
group: apps
version: v1
kind: Deployment
name: my-nginx
path: patch.yaml
EOF
执行 kubectl kustomize ./ 以查看 replicas 字段被更新:
apiVersion : apps/v1
kind : Deployment
metadata :
name : my-nginx
spec :
replicas : 3
selector :
matchLabels :
run : my-nginx
template :
metadata :
labels :
run : my-nginx
spec :
containers :
- image : nginx
name : my-nginx
ports :
- containerPort : 80
除了补丁之外,Kustomize 还提供定制容器镜像或者将其他对象的字段值注入到容器
中的能力,并且不需要创建补丁。
例如,你可以通过在 kustomization.yaml 文件的 images 字段设置新的镜像来
更改容器中使用的镜像。
cat <<EOF > deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-nginx
spec:
selector:
matchLabels:
run: my-nginx
replicas: 2
template:
metadata:
labels:
run: my-nginx
spec:
containers:
- name: my-nginx
image: nginx
ports:
- containerPort: 80
EOF
cat <<EOF >./kustomization.yaml
resources:
- deployment.yaml
images:
- name: nginx
newName: my.image.registry/nginx
newTag: 1.4.0
EOF
执行 kubectl kustomize ./ 以查看所使用的镜像已被更新:
apiVersion : apps/v1
kind : Deployment
metadata :
name : my-nginx
spec :
replicas : 2
selector :
matchLabels :
run : my-nginx
template :
metadata :
labels :
run : my-nginx
spec :
containers :
- image : my.image.registry/nginx:1.4.0
name : my-nginx
ports :
- containerPort : 80
有些时候,Pod 中运行的应用可能需要使用来自其他对象的配置值。
例如,某 Deployment 对象的 Pod 需要从环境变量或命令行参数中读取读取
Service 的名称。
由于在 kustomization.yaml 文件中添加 namePrefix 或 nameSuffix 时
Service 名称可能发生变化,建议不要在命令参数中硬编码 Service 名称。
对于这种使用场景,Kustomize 可以通过 vars 将 Service 名称注入到容器中。
# 创建一个 deployment.yaml 文件
cat <<EOF > deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-nginx
spec:
selector:
matchLabels:
run: my-nginx
replicas: 2
template:
metadata:
labels:
run: my-nginx
spec:
containers:
- name: my-nginx
image: nginx
command: ["start", "--host", "$(MY_SERVICE_NAME)"]
EOF
# 创建一个 service.yaml 文件
cat <<EOF > service.yaml
apiVersion: v1
kind: Service
metadata:
name: my-nginx
labels:
run: my-nginx
spec:
ports:
- port: 80
protocol: TCP
selector:
run: my-nginx
EOF
cat <<EOF >./kustomization.yaml
namePrefix: dev-
nameSuffix: "-001"
resources:
- deployment.yaml
- service.yaml
vars:
- name: MY_SERVICE_NAME
objref:
kind: Service
name: my-nginx
apiVersion: v1
EOF
执行 kubectl kustomize ./ 以查看注入到容器中的 Service 名称是 dev-my-nginx-001:
apiVersion : apps/v1
kind : Deployment
metadata :
name : dev-my-nginx-001
spec :
replicas : 2
selector :
matchLabels :
run : my-nginx
template :
metadata :
labels :
run : my-nginx
spec :
containers :
- command :
- start
- --host
- dev-my-nginx-001
image : nginx
name : my-nginx
基准(Bases)与覆盖(Overlays) Kustomize 中有 基准(bases) 和 覆盖(overlays) 的概念区分。
基准 是包含 kustomization.yaml 文件的一个目录,其中包含一组资源及其相关的定制。
基准可以是本地目录或者来自远程仓库的目录,只要其中存在 kustomization.yaml 文件即可。
覆盖 也是一个目录,其中包含将其他 kustomization 目录当做 bases 来引用的
kustomization.yaml 文件。
基准 不了解覆盖的存在,且可被多个覆盖所使用。
覆盖则可以有多个基准,且可针对所有基准中的资源执行组织操作,还可以在其上执行定制。
# 创建一个包含基准的目录
mkdir base
# 创建 base/deployment.yaml
cat <<EOF > base/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-nginx
spec:
selector:
matchLabels:
run: my-nginx
replicas: 2
template:
metadata:
labels:
run: my-nginx
spec:
containers:
- name: my-nginx
image: nginx
EOF
# 创建 base/service.yaml 文件
cat <<EOF > base/service.yaml
apiVersion: v1
kind: Service
metadata:
name: my-nginx
labels:
run: my-nginx
spec:
ports:
- port: 80
protocol: TCP
selector:
run: my-nginx
EOF
# 创建 base/kustomization.yaml
cat <<EOF > base/kustomization.yaml
resources:
- deployment.yaml
- service.yaml
EOF
此基准可在多个覆盖中使用。你可以在不同的覆盖中添加不同的 namePrefix 或
其他贯穿性字段。下面是两个使用同一基准的覆盖:
mkdir dev
cat <<EOF > dev/kustomization.yaml
bases:
- ../base
namePrefix: dev-
EOF
mkdir prod
cat <<EOF > prod/kustomization.yaml
bases:
- ../base
namePrefix: prod-
EOF
如何使用 Kustomize 来应用、查看和删除对象 在 kubectl 命令中使用 --kustomize 或 -k 参数来识别被 kustomization.yaml 所管理的资源。
注意 -k 要指向一个 kustomization 目录。例如:
kubectl apply -k <kustomization 目录>/
假定使用下面的 kustomization.yaml,
# 创建 deployment.yaml 文件
cat <<EOF > deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-nginx
spec:
selector:
matchLabels:
run: my-nginx
replicas: 2
template:
metadata:
labels:
run: my-nginx
spec:
containers:
- name: my-nginx
image: nginx
ports:
- containerPort: 80
EOF
# 创建 kustomization.yaml
cat <<EOF >./kustomization.yaml
namePrefix: dev-
commonLabels:
app: my-nginx
resources:
- deployment.yaml
EOF
执行下面的命令来应用 Deployment 对象 dev-my-nginx:
deployment.apps/dev-my-nginx created
运行下面的命令之一来查看 Deployment 对象 dev-my-nginx:
执行下面的命令来比较 Deployment 对象 dev-my-nginx 与清单被应用之后
集群将处于的状态:
执行下面的命令删除 Deployment 对象 dev-my-nginx:
deployment.apps "dev-my-nginx" deleted
Kustomize 功能特性列表 字段 类型 解释 namespace string 为所有资源添加名字空间 namePrefix string 此字段的值将被添加到所有资源名称前面 nameSuffix string 此字段的值将被添加到所有资源名称后面 commonLabels map[string]string 要添加到所有资源和选择算符的标签 commonAnnotations map[string]string 要添加到所有资源的注解 resources []string 列表中的每个条目都必须能够解析为现有的资源配置文件 configmapGenerator []ConfigMapArgs 列表中的每个条目都会生成一个 ConfigMap secretGenerator []SecretArgs 列表中的每个条目都会生成一个 Secret generatorOptions GeneratorOptions 更改所有 ConfigMap 和 Secret 生成器的行为 bases []string 列表中每个条目都应能解析为一个包含 kustomization.yaml 文件的目录 patchesStrategicMerge []string 列表中每个条目都能解析为某 Kubernetes 对象的策略性合并补丁 patchesJson6902 []Json6902 列表中每个条目都能解析为一个 Kubernetes 对象和一个 JSON 补丁 vars []Var 每个条目用来从某资源的字段来析取文字 images []Image 每个条目都用来更改镜像的名称、标记与/或摘要,不必生成补丁 configurations []string 列表中每个条目都应能解析为一个包含 Kustomize 转换器配置 的文件 crds []string 列表中每个条目都赢能够解析为 Kubernetes 类别的 OpenAPI 定义文件
接下来 4.4.3 - 使用指令式命令管理 Kubernetes 对象 使用构建在 kubectl 命令行工具中的指令式命令可以直接快速创建、更新和删除
Kubernetes 对象。本文档解释这些命令的组织方式以及如何使用它们来管理现时对象。
准备开始 安装kubectl 。
你必须拥有一个 Kubernetes 的集群,同时你的 Kubernetes 集群必须带有 kubectl 命令行工具。
如果你还没有集群,你可以通过 Minikube 构建一
个你自己的集群,或者你可以使用下面任意一个 Kubernetes 工具构建:
要获知版本信息,请输入
kubectl version.
权衡取舍 kubectl 工具能够支持三种对象管理方式:
关于每种对象管理的优缺点的讨论,可参见
Kubernetes 对象管理 。
如何创建对象 kubectl 工具支持动词驱动的命令,用来创建一些最常见的对象类别。
命令的名称设计使得不熟悉 Kubernetes 对象类型的用户也能做出判断。
run:创建一个新的 Pod 来运行一个容器。expose:创建一个新的 Service 对象为若干 Pod 提供流量负载均衡。autoscale:创建一个新的 Autoscaler 对象来自动对某控制器(如 Deployment)
执行水平扩缩。kubectl 命令也支持一些对象类型驱动的创建命令。
这些命令可以支持更多的对象类别,并且在其动机上体现得更为明显,不过要求
用户了解它们所要创建的对象的类别。
create <对象类别> [<子类别>] <实例名称>某些对象类别拥有自己的子类别,可以在 create 命令中设置。
例如,Service 对象有 ClusterIP、LoadBalancer 和 NodePort 三种子类别。
下面是一个创建 NodePort 子类别的 Service 的示例:
kubectl create service nodeport <服务名称>
在前述示例中,create service nodeport 命令也称作 create service
命令的子命令。
可以使用 -h 标志找到一个子命令所支持的参数和标志。
kubectl create service nodeport -h
如何更新对象 kubectl 命令也支持一些动词驱动的命令,用来执行一些常见的更新操作。
这些命令的设计是为了让一些不了解 Kubernetes 对象的用户也能执行更新操作,
但不需要了解哪些字段必须设置:
scale:对某控制器进行水平扩缩以便通过更新控制器的副本个数来添加或删除 Pod。annotate:为对象添加或删除注解。label:为对象添加或删除标签。kubectl 命令也支持由对象的某一方面来驱动的更新命令。
设置对象的这一方面可能对不同类别的对象意味着不同的字段:
说明: 在 Kubernetes 1.5 版本中,并非所有动词驱动的命令都有对应的方面驱动的命令。
kubectl 工具支持以下额外的方式用来直接更新现时对象,不过这些操作要求
用户对 Kubernetes 对象的模式定义有很好的了解:
edit:通过在编辑器中打开现时对象的配置,直接编辑其原始配置。patch:通过使用补丁字符串(Patch String)直接更改某现时对象的的特定字段。
关于补丁字符串的更详细信息,参见
API 约定
的 patch 节。如何删除对象 你可以使用 delete 命令从集群中删除一个对象:
你可以使用 kubectl delete 来执行指令式命令或者指令式对象配置。不同之处在于
传递给命令的参数。要将 kubectl delete 作为指令式命令使用,将要删除的对象作为
参数传递给它。下面是一个删除名为 nginx 的 Deployment 对象的命令:
kubectl delete deployment/nginx
如何查看对象 用来打印对象信息的命令有好几个:
get:打印匹配到的对象的基本信息。使用 get -h 可以查看选项列表。describe:打印匹配到的对象的详细信息的汇集版本。logs:打印 Pod 中运行的容器的 stdout 和 stderr 输出。使用 set 命令在创建对象之前修改对象 有些对象字段在 create 命令中没有对应的标志。在这些场景中,
你可以使用 set 和 create 命令的组合来在对象创建之前设置字段值。
这是通过将 create 命令的输出用管道方式传递给 set 命令来实现的,
最后执行 create 命令来创建对象。下面是一个例子:
kubectl create service clusterip my-svc --clusterip= "None" -o yaml --dry-run= client | kubectl set selector --local -f - 'environment=qa' -o yaml | kubectl create -f -
命令 kubectl create service -o yaml --dry-run=client 创建 Service 的配置,但
将其以 YAML 格式在标准输出上打印而不是发送给 API 服务器。 命令 kubectl set selector --local -f - -o yaml 从标准输入读入配置,并将更新后的
配置以 YAML 格式输出到标准输出。 命令 kubectl create -f - 使用标准输入上获得的配置创建对象。 在创建之前使用 --edit 更改对象 你可以用 kubectl create --edit 来在对象被创建之前执行任意的变更。
下面是一个例子:
kubectl create service clusterip my-svc --clusterip= "None" -o yaml --dry-run= client > /tmp/srv.yaml
kubectl create --edit -f /tmp/srv.yaml
命令 kubectl create service 创建 Service 的配置并将其保存到
/tmp/srv.yaml 文件。 命令 kubectl create --edit 在创建 Service 对象打开其配置文件进行编辑。 接下来 4.4.4 - 使用配置文件对 Kubernetes 对象进行命令式管理 可以使用 kubectl 命令行工具以及用 YAML 或 JSON 编写的对象配置文件来创建、更新和删除 Kubernetes 对象。
本文档说明了如何使用配置文件定义和管理对象。
准备开始 安装 kubectl 。
你必须拥有一个 Kubernetes 的集群,同时你的 Kubernetes 集群必须带有 kubectl 命令行工具。
如果你还没有集群,你可以通过 Minikube 构建一
个你自己的集群,或者你可以使用下面任意一个 Kubernetes 工具构建:
要获知版本信息,请输入
kubectl version.
权衡 kubectl 工具支持三种对象管理:
参看 Kubernetes 对象管理
中关于每种对象管理的优缺点的讨论。
如何创建对象 你可以使用 kubectl create -f 从配置文件创建一个对象。
请参考 kubernetes API 参考 有关详细信息。
kubectl create -f <filename|url>如何更新对象 警告: 使用 replace 命令更新对象会删除所有未在配置文件中指定的规范的某些部分。
不应将其规范由集群部分管理的对象使用,比如类型为 LoadBalancer 的服务,
其中 externalIPs 字段独立于配置文件进行管理。
必须将独立管理的字段复制到配置文件中,以防止 replace 删除它们。
你可以使用 kubectl replace -f 根据配置文件更新活动对象。
kubectl replace -f <filename|url>如何删除对象 你可以使用 kubectl delete -f 删除配置文件中描述的对象。
kubectl delete -f <filename|url>说明: 如果配置文件在 metadata 节中设置了 generateName 字段而非 name 字段,
你无法使用 kubectl delete -f <filename|url> 来删除该对象。
你必须使用其他标志才能删除对象。例如:
kubectl delete <type> <name>
kubectl delete <type> -l <label>
如何查看对象 你可以使用 kubectl get -f 查看有关配置文件中描述的对象的信息。
kubectl get -f <filename|url> -o yaml-o yaml 标志指定打印完整的对象配置。
使用 kubectl get -h 查看选项列表。
局限性 当完全定义每个对象的配置并将其记录在其配置文件中时,create、 replace 和delete 命令会很好的工作。
但是,当更新一个活动对象,并且更新没有合并到其配置文件中时,下一次执行 replace 时,更新将丢失。
如果控制器,例如 HorizontalPodAutoscaler ,直接对活动对象进行更新,则会发生这种情况。
这有一个例子:
从配置文件创建一个对象。 另一个源通过更改某些字段来更新对象。 从配置文件中替换对象。在步骤2中所做的其他源的更改将丢失。 如果需要支持同一对象的多个编写器,则可以使用 kubectl apply 来管理该对象。
从 URL 创建和编辑对象而不保存配置 假设你具有对象配置文件的 URL。
你可以在创建对象之前使用 kubectl create --edit 对配置进行更改。
这对于指向可以由读者修改的配置文件的教程和任务特别有用。
kubectl create -f <url> --edit
从命令式命令迁移到命令式对象配置 从命令式命令迁移到命令式对象配置涉及几个手动步骤。
将活动对象导出到本地对象配置文件:
kubectl get <kind>/<name> -o yaml > <kind>_<name>.yaml
从对象配置文件中手动删除状态字段。 对于后续的对象管理,只能使用 replace 。
kubectl replace -f <kind>_<name>.yaml
定义控制器选择器和 PodTemplate 标签 警告: 不建议在控制器上更新选择器。
推荐的方法是定义单个不变的 PodTemplate 标签,该标签仅由控制器选择器使用,而没有其他语义。
标签示例:
selector :
matchLabels :
controller-selector : "apps/v1/deployment/nginx"
template :
metadata :
labels :
controller-selector : "apps/v1/deployment/nginx"
接下来 4.4.5 - 使用 kubectl patch 更新 API 对象 使用 kubectl patch 更新 Kubernetes API 对象。做一个策略性的合并 patch 或 JSON 合并 patch。
这个任务展示如何使用 kubectl patch 就地更新 API 对象。
这个任务中的练习演示了一个策略性合并 patch 和一个 JSON 合并 patch。
准备开始
你必须拥有一个 Kubernetes 的集群,同时你的 Kubernetes 集群必须带有 kubectl 命令行工具。
如果你还没有集群,你可以通过 Minikube 构建一
个你自己的集群,或者你可以使用下面任意一个 Kubernetes 工具构建:
要获知版本信息,请输入
kubectl version.
使用策略合并 patch 更新 Deployment 下面是具有两个副本的 Deployment 的配置文件。每个副本是一个 Pod,有一个容器:
apiVersion : apps/v1
kind : Deployment
metadata :
name : patch-demo
spec :
replicas : 2
selector :
matchLabels :
app : nginx
template :
metadata :
labels :
app : nginx
spec :
containers :
- name : patch-demo-ctr
image : nginx
tolerations :
- effect : NoSchedule
key : dedicated
value : test-team
创建 Deployment:
kubectl create -f https://k8s.io/examples/application/deployment-patch.yaml
查看与 Deployment 相关的 Pod:
输出显示 Deployment 有两个 Pod。1/1 表示每个 Pod 有一个容器:
NAME READY STATUS RESTARTS AGE
patch-demo-28633765-670qr 1/1 Running 0 23s
patch-demo-28633765-j5qs3 1/1 Running 0 23s
把运行的 Pod 的名字记下来。稍后,你将看到这些 Pod 被终止并被新的 Pod 替换。
此时,每个 Pod 都有一个运行 nginx 镜像的容器。现在假设你希望每个 Pod 有两个容器:一个运行 nginx,另一个运行 redis。
创建一个名为 patch-file-containers.yaml 的文件。内容如下:
spec :
template :
spec :
containers :
- name : patch-demo-ctr-2
image : redis
修补你的 Deployment:
kubectl patch deployment patch-demo --patch " $( cat patch-file-containers.yaml) "
查看修补后的 Deployment:
kubectl get deployment patch-demo --output yaml
输出显示 Deployment 中的 PodSpec 有两个容器:
containers :
- image : redis
imagePullPolicy : Always
name : patch-demo-ctr-2
...
- image : nginx
imagePullPolicy : Always
name : patch-demo-ctr
...
查看与 patch Deployment 相关的 Pod:
输出显示正在运行的 Pod 与以前运行的 Pod 有不同的名称。Deployment 终止了旧的 Pod,并创建了两个
符合更新的部署规范的新 Pod。2/2 表示每个 Pod 有两个容器:
NAME READY STATUS RESTARTS AGE
patch-demo-1081991389-2wrn5 2/2 Running 0 1m
patch-demo-1081991389-jmg7b 2/2 Running 0 1m
仔细查看其中一个 patch-demo Pod:
kubectl get pod <your-pod-name> --output yaml
输出显示 Pod 有两个容器:一个运行 nginx,一个运行 redis:
containers:
- image: redis
...
- image: nginx
...
策略性合并类的 patch 的说明 你在前面的练习中所做的 patch 称为策略性合并 patch(Strategic Merge Patch)。
请注意,patch 没有替换containers 列表。相反,它向列表中添加了一个新 Container。换句话说,
patch 中的列表与现有列表合并。当你在列表中使用策略性合并 patch 时,并不总是这样。
在某些情况下,列表是替换的,而不是合并的。
对于策略性合并 patch,列表可以根据其 patch 策略进行替换或合并。
patch 策略由 Kubernetes 源代码中字段标记中的 patchStrategy 键的值指定。
例如,PodSpec 结构体的 Containers 字段的 patchStrategy 为 merge:
type PodSpec struct {
...
Containers []Container `json:"containers" patchStrategy:"merge" patchMergeKey:"name" ...`
你还可以在 OpenApi spec
规范中看到 patch 策略:
"io.k8s.api.core.v1.PodSpec" : {
...
"containers" : {
"description" : "List of containers belonging to the pod. ...
},
" x-kubernetes-patch-merge-key ": " name ",
" x-kubernetes-patch-strategy ": " merge"
},
你可以在 Kubernetes API 文档
中看到 patch 策略。
创建一个名为 patch-file-tolerations.yaml 的文件。内容如下:
spec :
template :
spec :
tolerations :
- effect : NoSchedule
key : disktype
value : ssd
对 Deployment 执行 patch 操作:
kubectl patch deployment patch-demo --patch "$(cat patch-file-containers.yaml)"
查看修补后的 Deployment:
kubectl get deployment patch-demo --output yaml
输出结果显示 Deployment 中的 PodSpec 只有一个容忍度设置:
containers:
- image: redis
imagePullPolicy: Always
name: patch-demo-ctr-2
...
- image: nginx
imagePullPolicy: Always
name: patch-demo-ctr
...
tolerations:
- effect: NoSchedule
key: disktype
value: ssd
请注意,PodSpec 中的 tolerations 列表被替换,而不是合并。这是因为 PodSpec 的 tolerations
的字段标签中没有 patchStrategy 键。所以策略合并 patch 操作使用默认的 patch 策略,也就是 replace。
type PodSpec struct {
...
Tolerations []Toleration `json:"tolerations,omitempty" protobuf:"bytes,22,opt,name=tolerations"`
使用 JSON 合并 patch 更新 Deployment 策略性合并 patch 不同于 JSON 合并 patch 。
使用 JSON 合并 patch,如果你想更新列表,你必须指定整个新列表。新的列表完全取代现有的列表。
kubectl patch 命令有一个 type 参数,你可以将其设置为以下值之一:
有关 JSON patch 和 JSON 合并 patch 的比较,查看
JSON patch 和 JSON 合并 patch 。
type 参数的默认值是 strategic。在前面的练习中,我们做了一个策略性的合并 patch。
下一步,在相同的 Deployment 上执行 JSON 合并 patch。创建一个名为 patch-file-2 的文件。内容如下:
spec :
template :
spec :
containers :
- name : patch-demo-ctr-3
image : gcr.io/google-samples/node-hello:1.0
在 patch 命令中,将 type 设置为 merge:
kubectl patch deployment patch-demo --type merge --patch " $( cat patch-file-2.yaml) "
查看修补后的 Deployment:
kubectl get deployment patch-demo --output yaml
patch 中指定的containers列表只有一个 Container。
输出显示你所给出的 Contaier 列表替换了现有的 containers 列表。
spec :
containers :
- image : gcr.io/google-samples/node-hello:1.0
...
name : patch-demo-ctr-3
列表中运行的 Pod:
在输出中,你可以看到已经终止了现有的 Pod,并创建了新的 Pod。1/1 表示每个新 Pod只运行一个容器。
NAME READY STATUS RESTARTS AGE
patch-demo-1307768864-69308 1/1 Running 0 1m
patch-demo-1307768864-c86dc 1/1 Running 0 1m
使用带 retainKeys 策略的策略合并 patch 更新 Deployment apiVersion : apps/v1
kind : Deployment
metadata :
name : retainkeys-demo
spec :
selector :
matchLabels :
app : nginx
strategy :
rollingUpdate :
maxSurge : 30 %
template :
metadata :
labels :
app : nginx
spec :
containers :
- name : retainkeys-demo-ctr
image : nginx
创建 Deployment:
kubectl apply -f https://k8s.io/examples/application/deployment-retainkeys.yaml
这时,Deployment 被创建,并使用 RollingUpdate 策略。
创建一个名为 patch-file-no-retainkeys.yaml 的文件,内容如下:
spec :
strategy :
type : Recreate
修补你的 Deployment:
kubectl patch deployment retainkeys-demo --patch " $( cat patch-file-no-retainkeys.yaml) "
kubectl patch deployment retainkeys-demo --patch $(Get-Content patch-file -no-retainkeys.yaml -Raw)
在输出中,你可以看到,当 spec.strategy.rollingUpdate 已经拥有取值定义时,
将其 type 设置为 Recreate 是不可能的。
The Deployment "retainkeys-demo" is invalid: spec.strategy.rollingUpdate: Forbidden: may not be specified when strategy ` type ` is 'Recreate'
更新 type 取值的同时移除 spec.strategy.rollingUpdate 现有值的方法是
为策略性合并操作设置 retainKeys 策略:
创建另一个名为 patch-file-retainkeys.yaml 的文件,内容如下:
spec :
strategy :
$retainKeys :
- type
type : Recreate
使用此 patch,我们表达了希望只保留 strategy 对象的 type 键。
这样,在 patch 操作期间 rollingUpdate 会被删除。
使用新的 patch 重新修补 Deployment:
kubectl patch deployment retainkeys-demo --patch " $( cat patch-file-retainkeys.yaml) "
kubectl patch deployment retainkeys-demo --patch $(Get-Content patch-file -retainkeys.yaml -Raw)
检查 Deployment 的内容:
kubectl get deployment retainkeys-demo --output yaml
输出显示 Deployment 中的 strategy 对象不再包含 rollingUpdate 键:
spec:
strategy:
type: Recreate
template:
关于使用 retainKeys 策略的策略合并 patch 操作的说明 在前文练习中所执行的称作 带 retainKeys 策略的策略合并 patch(Strategic Merge
Patch with retainKeys Strategy) 。
这种方法引入了一种新的 $retainKey 指令,具有如下策略:
其中包含一个字符串列表; 所有需要被保留的字段必须在 $retainKeys 列表中给出; 对于已有的字段,会和对象上对应的内容合并; 在修补操作期间,未找到的字段都会被清除; 列表 $retainKeys 中的所有字段必须 patch 操作所给字段的超集,或者与之完全一致。 策略 retainKeys 并不能对所有对象都起作用。它仅对那些 Kubernetes 源码中
patchStrategy 字段标志值包含 retainKeys 的字段有用。
例如 DeploymentSpec 结构的 Strategy 字段就包含了 patchStrategy 为
retainKeys 的标志。
type DeploymentSpec struct {
...
// +patchStrategy=retainKeys
Strategy DeploymentStrategy `json:"strategy,omitempty" patchStrategy:"retainKeys" ...`
你也可以查看 OpenAPI 规范 中的 retainKeys 策略:
"io.k8s.api.apps.v1.DeploymentSpec" : {
...
"strategy" : {
"$ref" : "#/definitions/io.k8s.api.apps.v1.DeploymentStrategy" ,
"description" : "The deployment strategy to use to replace existing pods with new ones." ,
"x-kubernetes-patch-strategy" : "retainKeys"
},
而且你也可以在
Kubernetes API 文档 .
中看到 retainKey 策略。
kubectl patch 命令的其他形式 kubectl patch 命令使用 YAML 或 JSON。它可以接受以文件形式提供的补丁,也可以
接受直接在命令行中给出的补丁。
创建一个文件名称是 patch-file.json 内容如下:
{
"spec" : {
"template" : {
"spec" : {
"containers" : [
{
"name" : "patch-demo-ctr-2" ,
"image" : "redis"
}
]
}
}
}
}
以下命令是等价的:
kubectl patch deployment patch-demo --patch " $( cat patch-file.yaml) "
kubectl patch deployment patch-demo --patch 'spec:\n template:\n spec:\n containers:\n - name: patch-demo-ctr-2\n image: redis'
kubectl patch deployment patch-demo --patch " $( cat patch-file.json) "
kubectl patch deployment patch-demo --patch '{"spec": {"template": {"spec": {"containers": [{"name": "patch-demo-ctr-2","image": "redis"}]}}}}'
总结 在本练习中,你使用 kubectl patch 更改了 Deployment 对象的当前配置。
你没有更改最初用于创建 Deployment 对象的配置文件。
用于更新 API 对象的其他命令包括
kubectl annotate ,
kubectl edit ,
kubectl replace ,
kubectl scale ,
和
kubectl apply 。
说明: 定制资源不支持策略性合并 patch。
接下来 4.5 - 管理 Secrets 使用 Secrets 管理机密配置数据。
4.5.1 - 使用 kubectl 管理 Secret 使用 kubectl 命令行创建 Secret 对象。
准备开始 你必须拥有一个 Kubernetes 的集群,同时你的 Kubernetes 集群必须带有 kubectl 命令行工具。
如果你还没有集群,你可以通过 Minikube 构建一
个你自己的集群,或者你可以使用下面任意一个 Kubernetes 工具构建:
创建 Secret 一个 Secret 可以包含 Pod 访问数据库所需的用户凭证。
例如,由用户名和密码组成的数据库连接字符串。
你可以在本地计算机上,将用户名存储在文件 ./username.txt 中,将密码存储在文件 ./password.txt 中。
echo -n 'admin' > ./username.txt
echo -n '1f2d1e2e67df' > ./password.txt
上面两个命令中的 -n 标志确保生成的文件在文本末尾不包含额外的换行符。
这一点很重要,因为当 kubectl 读取文件并将内容编码为 base64 字符串时,多余的换行符也会被编码。
kubectl create secret 命令将这些文件打包成一个 Secret 并在 API 服务器上创建对象。
kubectl create secret generic db-user-pass \
--from-file= ./username.txt \
--from-file= ./password.txt
输出类似于:
secret/db-user-pass created
默认密钥名称是文件名。 你可以选择使用 --from-file=[key=]source 来设置密钥名称。例如:
kubectl create secret generic db-user-pass \
--from-file= username = ./username.txt \
--from-file= password = ./password.txt
你无需转义文件(--from-file)中的密码的特殊字符。
你还可以使用 --from-literal=<key>=<value> 标签提供 Secret 数据。
可以多次使用此标签,提供多个键值对。
请注意,特殊字符(例如:$,\,*,= 和 !)由你的 shell 解释执行,而且需要转义。
在大多数 shell 中,转义密码最简便的方法是用单引号括起来。
比如,如果你的密码是 S!B\*d$zDsb=,
可以像下面一样执行命令:
kubectl create secret generic dev-db-secret \
--from-literal= username = devuser \
--from-literal= password = 'S!B\*d$zDsb='
验证 Secret 你可以检查 secret 是否已创建:
输出类似于:
NAME TYPE DATA AGE
db-user-pass Opaque 2 51s
你可以查看 Secret 的描述:
kubectl describe secrets/db-user-pass
输出类似于:
Name: db-user-pass
Namespace: default
Labels: <none>
Annotations: <none>
Type: Opaque
Data
====
password: 12 bytes
username: 5 bytes
kubectl get 和 kubectl describe 命令默认不显示 Secret 的内容。
这是为了防止 Secret 被意外暴露给旁观者或存储在终端日志中。
解码 Secret 要查看我们刚刚创建的 Secret 的内容,可以运行以下命令:
kubectl get secret db-user-pass -o jsonpath = '{.data}'
输出类似于:
{"password" :"MWYyZDFlMmU2N2Rm" ,"username" :"YWRtaW4=" }
现在你可以解码 password 的数据:
echo 'MWYyZDFlMmU2N2Rm' | base64 --decode
输出类似于:
1f2d1e2e67df
清理 删除刚刚创建的 Secret:
kubectl delete secret db-user-pass
接下来 4.5.2 - 使用配置文件管理 Secret 使用资源配置文件创建 Secret 对象。
准备开始 你必须拥有一个 Kubernetes 的集群,同时你的 Kubernetes 集群必须带有 kubectl 命令行工具。
如果你还没有集群,你可以通过 Minikube 构建一
个你自己的集群,或者你可以使用下面任意一个 Kubernetes 工具构建:
创建配置文件 你可以先用 JSON 或 YAML 格式在文件中创建 Secret,然后创建该对象。
Secret
资源包含2个键值对: data 和 stringData。
data 字段用来存储 base64 编码的任意数据。
提供 stringData 字段是为了方便,它允许 Secret 使用未编码的字符串。
data 和 stringData 的键必须由字母、数字、-,_ 或 . 组成。
例如,要使用 Secret 的 data 字段存储两个字符串,请将字符串转换为 base64 ,如下所示:
输出类似于:
YWRtaW4=
echo -n '1f2d1e2e67df' | base64
输出类似于:
MWYyZDFlMmU2N2Rm
编写一个 Secret 配置文件,如下所示:
apiVersion : v1
kind : Secret
metadata :
name : mysecret
type : Opaque
data :
username : YWRtaW4=
password : MWYyZDFlMmU2N2Rm
注意,Secret 对象的名称必须是有效的 DNS 子域名 .
说明: Secret 数据的 JSON 和 YAML 序列化结果是以 base64 编码的。
换行符在这些字符串中无效,必须省略。
在 Darwin/macOS 上使用 base64 工具时,用户不应该使用 -b 选项分割长行。
相反地,Linux 用户 应该 在 base64 地命令中添加 -w 0 选项,
或者在 -w 选项不可用的情况下,输入 base64 | tr -d '\n'。
对于某些场景,你可能希望使用 stringData 字段。
这字段可以将一个非 base64 编码的字符串直接放入 Secret 中,
当创建或更新该 Secret 时,此字段将被编码。
上述用例的实际场景可能是这样:当你部署应用时,使用 Secret 存储配置文件,
你希望在部署过程中,填入部分内容到该配置文件。
例如,如果你的应用程序使用以下配置文件:
apiUrl : "https://my.api.com/api/v1"
username : "<user>"
password : "<password>"
你可以使用以下定义将其存储在 Secret 中:
apiVersion : v1
kind : Secret
metadata :
name : mysecret
type : Opaque
stringData :
config.yaml : |
apiUrl: "https://my.api.com/api/v1"
username: <user>
password: <password>
创建 Secret 对象 现在使用 kubectl apply 创建 Secret:
kubectl apply -f ./secret.yaml
输出类似于:
secret/mysecret created
检查 Secret stringData 字段是只写的。获取 Secret 时,此字段永远不会输出。
例如,如果你运行以下命令:
kubectl get secret mysecret -o yaml
输出类似于:
apiVersion : v1
kind : Secret
metadata :
creationTimestamp : 2018-11-15T20:40:59Z
name : mysecret
namespace : default
resourceVersion : "7225"
uid : c280ad2e-e916-11e8-98f2-025000000001
type : Opaque
data :
config.yaml : YXBpVXJsOiAiaHR0cHM6Ly9teS5hcGkuY29tL2FwaS92MSIKdXNlcm5hbWU6IHt7dXNlcm5hbWV9fQpwYXNzd29yZDoge3twYXNzd29yZH19
命令 kubectl get 和 kubectl describe 默认不显示 Secret 的内容。
这是为了防止 Secret 意外地暴露给旁观者或者保存在终端日志中。
检查编码数据的实际内容,请参考解码 secret .
如果在 data 和 stringData 中都指定了一个字段,比如 username,字段值来自 stringData。
例如,下面的 Secret 定义:
apiVersion : v1
kind : Secret
metadata :
name : mysecret
type : Opaque
data :
username : YWRtaW4=
stringData :
username : administrator
结果有以下 Secret:
apiVersion : v1
kind : Secret
metadata :
creationTimestamp : 2018-11-15T20:46:46Z
name : mysecret
namespace : default
resourceVersion : "7579"
uid : 91460ecb-e917-11e8-98f2-025000000001
type : Opaque
data :
username : YWRtaW5pc3RyYXRvcg==
其中 YWRtaW5pc3RyYXRvcg== 解码成 administrator。
清理 删除你刚才创建的 Secret:
kubectl delete secret mysecret
接下来 4.5.3 - 使用 Kustomize 管理 Secret 使用 kustomization.yaml 文件创建 Secret 对象。
从 kubernetes v1.14 开始,kubectl 支持使用 Kustomize 管理对象 。
Kustomize 提供了资源生成器(Generators)来创建 Secret 和 ConfigMap。
Kustomize 生成器应该在某个目录的 kustomization.yaml 文件中指定。
生成 Secret 后,你可以使用 kubectl apply 在 API 服务器上创建该 Secret。
准备开始 你必须拥有一个 Kubernetes 的集群,同时你的 Kubernetes 集群必须带有 kubectl 命令行工具。
如果你还没有集群,你可以通过 Minikube 构建一
个你自己的集群,或者你可以使用下面任意一个 Kubernetes 工具构建:
创建 Kustomization 文件 你可以在 kustomization.yaml 中定义 secreteGenerator,并在定义中引用其他现成的文件,生成 Secret。
例如:下面的 kustomization 文件 引用了 ./username.txt 和 ./password.txt 文件:
secretGenerator :
- name : db-user-pass
files :
- username.txt
- password.txt
你也可以在 kustomization.yaml 文件中指定一些字面量定义 secretGenerator。
例如:下面的 kustomization.yaml 文件中包含了 username 和 password 两个字面量:
secretGenerator :
- name : db-user-pass
literals :
- username=admin
- password=1f2d1e2e67df
注意,上面两种情况,你都不需要使用 base64 编码。
创建 Secret 使用 kubectl apply 命令应用包含 kustomization.yaml 文件的目录创建 Secret。
输出类似于:
secret/db-user-pass-96mffmfh4k created
请注意,生成 Secret 时,Secret 的名称最终是由 name 字段和数据的哈希值拼接而成。
这将保证每次修改数据时生成一个新的 Secret。
检查创建的 Secret 你可以检查刚才创建的 Secret:
输出类似于:
NAME TYPE DATA AGE
db-user-pass-96mffmfh4k Opaque 2 51s
你可以看到 Secret 的描述:
kubectl describe secrets/db-user-pass-96mffmfh4k
输出类似于:
Name: db-user-pass
Namespace: default
Labels: <none>
Annotations: <none>
Type: Opaque
Data
====
password.txt: 12 bytes
username.txt: 5 bytes
kubectl get 和 kubectl describe 命令默认不显示 Secret 的内容。
这是为了防止 Secret 被意外暴露给旁观者或存储在终端日志中。
检查编码后的实际内容,请参考解码 secret 。
-->
清理 删除你刚才创建的 Secret:
kubectl delete secret db-user-pass-96mffmfh4k
接下来 4.6 - 给应用注入数据 给你的工作负载 Pod 指定配置和其他数据。
4.6.1 - 为容器设置启动时要执行的命令和参数 本页将展示如何为 Pod
中容器设置启动时要执行的命令及其参数。
准备开始
你必须拥有一个 Kubernetes 的集群,同时你的 Kubernetes 集群必须带有 kubectl 命令行工具。
如果你还没有集群,你可以通过 Minikube 构建一
个你自己的集群,或者你可以使用下面任意一个 Kubernetes 工具构建:
要获知版本信息,请输入
kubectl version.
创建 Pod 时设置命令及参数 创建 Pod 时,可以为其下的容器设置启动时要执行的命令及其参数。如果要设置命令,就填写在配置文件的 command 字段下,如果要设置命令的参数,就填写在配置文件的 args 字段下。一旦 Pod 创建完成,该命令及其参数就无法再进行更改了。
如果在配置文件中设置了容器启动时要执行的命令及其参数,那么容器镜像中自带的命令与参数将会被覆盖而不再执行。如果配置文件中只是设置了参数,却没有设置其对应的命令,那么容器镜像中自带的命令会使用该新参数作为其执行时的参数。
说明: 在有些容器运行时中,
command 字段对应
entrypoint,请参阅下面的
说明事项 。
本示例中,将创建一个只包含单个容器的 Pod。在 Pod 配置文件中设置了一个命令与两个参数:
apiVersion : v1
kind : Pod
metadata :
name : command-demo
labels :
purpose : demonstrate-command
spec :
containers :
- name : command-demo-container
image : debian
command : ["printenv" ]
args : ["HOSTNAME" , "KUBERNETES_PORT" ]
restartPolicy : OnFailure
基于 YAML 文件创建一个 Pod:
kubectl apply -f https://k8s.io/examples/pods/commands.yaml
获取正在运行的 Pods:
查询结果显示在 command-demo 这个 Pod 下运行的容器已经启动完成。
如果要获取容器启动时执行命令的输出结果,可以通过 Pod 的日志进行查看:
kubectl logs command-demo
日志中显示了 HOSTNAME 与 KUBERNETES_PORT 这两个环境变量的值:
command-demo
tcp://10.3.240.1:443
使用环境变量来设置参数 在上面的示例中,我们直接将一串字符作为命令的参数。除此之外,我们还可以将环境变量作为命令的参数。
env :
- name : MESSAGE
value : "hello world"
command : ["/bin/echo" ]
args : ["$(MESSAGE)" ]
这意味着你可以将那些用来设置环境变量的方法应用于设置命令的参数,其中包括了
ConfigMaps 与
Secrets 。
说明: 环境变量需要加上括号,类似于 "$(VAR)"。这是在 command 或 args 字段使用变量的格式要求。
在 Shell 来执行命令 有时候,你需要在 Shell 脚本中运行命令。
例如,你要执行的命令可能由多个命令组合而成,或者它就是一个 Shell 脚本。
这时,就可以通过如下方式在 Shell 中执行命令:
command: [ "/bin/sh" ]
args: [ "-c" , "while true; do echo hello; sleep 10;done" ]
说明事项 下表给出了 Docker 与 Kubernetes 中对应的字段名称。
描述 Docker 字段名称 Kubernetes 字段名称 容器执行的命令 Entrypoint command 传给命令的参数 Cmd args
如果要覆盖默认的 Entrypoint 与 Cmd,需要遵循如下规则:
如果在容器配置中没有设置 command 或者 args,那么将使用 Docker 镜像自带的命令及其参数。
如果在容器配置中只设置了 command 但是没有设置 args,那么容器启动时只会执行该命令,
Docker 镜像中自带的命令及其参数会被忽略。
如果在容器配置中只设置了 args,那么 Docker 镜像中自带的命令会使用该新参数作为其执行时的参数。
如果在容器配置中同时设置了 command 与 args,那么 Docker 镜像中自带的命令及其参数会被忽略。
容器启动时只会执行配置中设置的命令,并使用配置中设置的参数作为命令的参数。
下面是一些例子:
镜像 Entrypoint 镜像 Cmd 容器 command 容器 args 命令执行 [/ep-1][foo bar]<not set> <not set> [ep-1 foo bar][/ep-1][foo bar][/ep-2]<not set> [ep-2][/ep-1][foo bar]<not set> [zoo boo][ep-1 zoo boo][/ep-1][foo bar][/ep-2][zoo boo][ep-2 zoo boo]
接下来 4.6.2 - 为容器设置环境变量 本页将展示如何为 kubernetes Pod 下的容器设置环境变量。
准备开始 你必须拥有一个 Kubernetes 的集群,同时你的 Kubernetes 集群必须带有 kubectl 命令行工具。
如果你还没有集群,你可以通过 Minikube 构建一
个你自己的集群,或者你可以使用下面任意一个 Kubernetes 工具构建:
为容器设置一个环境变量 创建 Pod 时,可以为其下的容器设置环境变量。通过配置文件的 env 或者 envFrom 字段来设置环境变量。
本示例中,将创建一个只包含单个容器的 Pod。Pod 的配置文件中设置环境变量的名称为 DEMO_GREETING,
其值为 "Hello from the environment"。下面是 Pod 的配置文件内容:
apiVersion : v1
kind : Pod
metadata :
name : envar-demo
labels :
purpose : demonstrate-envars
spec :
containers :
- name : envar-demo-container
image : gcr.io/google-samples/node-hello:1.0
env :
- name : DEMO_GREETING
value : "Hello from the environment"
- name : DEMO_FAREWELL
value : "Such a sweet sorrow"
基于 YAML 文件创建一个 Pod:
kubectl apply -f https://k8s.io/examples/pods/inject/envars.yaml
获取一下当前正在运行的 Pods 信息:
kubectl get pods -l purpose = demonstrate-envars
查询结果应为:
NAME READY STATUS RESTARTS AGE
envar-demo 1/1 Running 0 9s
列出 Pod 容器的环境变量:
kubectl exec envar-demo -- printenv
打印结果应为:
NODE_VERSION = 4.4.2
EXAMPLE_SERVICE_PORT_8080_TCP_ADDR = 10.3.245.237
HOSTNAME = envar-demo
...
DEMO_GREETING = Hello from the environment
DEMO_FAREWELL = Such a sweet sorrow
说明: 通过 env 或 envFrom 字段设置的环境变量将覆盖容器镜像中指定的所有环境变量。
说明: 环境变量之间可能出现互相依赖或者循环引用的情况,使用之前需注意引用顺序
在配置中使用环境变量 您在 Pod 的配置中定义的环境变量可以在配置的其他地方使用,例如可用在为 Pod 的容器设置的命令和参数中。在下面的示例配置中,环境变量 GREETING ,HONORIFIC 和 NAME 分别设置为 Warm greetings to ,The Most Honorable 和 Kubernetes。然后这些环境变量在传递给容器 env-print-demo 的 CLI 参数中使用。
apiVersion : v1
kind : Pod
metadata :
name : print-greeting
spec :
containers :
- name : env-print-demo
image : bash
env :
- name : GREETING
value : "Warm greetings to"
- name : HONORIFIC
value : "The Most Honorable"
- name : NAME
value : "Kubernetes"
command : ["echo" ]
args : ["$(GREETING) $(HONORIFIC) $(NAME)" ]
创建后,命令 echo Warm greetings to The Most Honorable Kubernetes 将在容器中运行。
接下来 4.6.3 - 定义相互依赖的环境变量 本页展示了如何为 Kubernetes Pod 中的容器定义相互依赖的环境变量。
准备开始 你必须拥有一个 Kubernetes 的集群,同时你的 Kubernetes 集群必须带有 kubectl 命令行工具。
如果你还没有集群,你可以通过 Minikube 构建一
个你自己的集群,或者你可以使用下面任意一个 Kubernetes 工具构建:
为容器定义相互依赖的环境变量 当创建一个 Pod 时,你可以为运行在 Pod 中的容器设置相互依赖的环境变量。
设置相互依赖的环境变量,你就可以在配置清单文件的 env 的 value 中使用 $(VAR_NAME)。
在本练习中,你会创建一个单容器的 Pod。
此 Pod 的配置文件定义了一个已定义常用用法的相互依赖的环境变量。
下面是 Pod 的配置清单:
apiVersion : v1
kind : Pod
metadata :
name : dependent-envars-demo
spec :
containers :
- name : dependent-envars-demo
args :
- while true; do echo -en '\n'; printf UNCHANGED_REFERENCE=$UNCHANGED_REFERENCE'\n'; printf SERVICE_ADDRESS=$SERVICE_ADDRESS'\n';printf ESCAPED_REFERENCE=$ESCAPED_REFERENCE'\n'; sleep 30; done;
command :
- sh
- -c
image : busybox
env :
- name : SERVICE_PORT
value : "80"
- name : SERVICE_IP
value : "172.17.0.1"
- name : UNCHANGED_REFERENCE
value : "$(PROTOCOL)://$(SERVICE_IP):$(SERVICE_PORT)"
- name : PROTOCOL
value : "https"
- name : SERVICE_ADDRESS
value : "$(PROTOCOL)://$(SERVICE_IP):$(SERVICE_PORT)"
- name : ESCAPED_REFERENCE
value : "$$(PROTOCOL)://$(SERVICE_IP):$(SERVICE_PORT)"
依据清单创建 Pod:
kubectl apply -f https://k8s.io/examples/pods/inject/dependent-envars.yaml
pod/dependent-envars-demo created
列出运行的 Pod:
kubectl get pods dependent-envars-demo
NAME READY STATUS RESTARTS AGE
dependent-envars-demo 1/1 Running 0 9s
检查 Pod 中运行容器的日志:
kubectl logs pod/dependent-envars-demo
UNCHANGED_REFERENCE=$(PROTOCOL)://172.17.0.1:80
SERVICE_ADDRESS=https://172.17.0.1:80
ESCAPED_REFERENCE=$(PROTOCOL)://172.17.0.1:80
如上所示,你已经定义了 SERVICE_ADDRESS 的正确依赖引用,
UNCHANGED_REFERENCE 的错误依赖引用,
并跳过了 ESCAPED_REFERENCE 的依赖引用。
如果环境变量被引用时已事先定义,则引用可以正确解析,
比如 SERVICE_ADDRESS 的例子。
当环境变量未定义或仅包含部分变量时,未定义的变量会被当做普通字符串对待,
比如 UNCHANGED_REFERENCE 的例子。
注意,解析不正确的环境变量通常不会阻止容器启动。
$(VAR_NAME) 这样的语法可以用两个 $ 转义,既:$$(VAR_NAME)。
无论引用的变量是否定义,转义的引用永远不会展开。
这一点可以从上面 ESCAPED_REFERENCE 的例子得到印证。
接下来 4.6.4 - 通过环境变量将 Pod 信息呈现给容器 此页面展示 Pod 如何使用环境变量把自己的信息呈现给 Pod 中运行的容器。
环境变量可以呈现 Pod 的字段和容器字段。
准备开始
你必须拥有一个 Kubernetes 的集群,同时你的 Kubernetes 集群必须带有 kubectl 命令行工具。
如果你还没有集群,你可以通过 Minikube 构建一
个你自己的集群,或者你可以使用下面任意一个 Kubernetes 工具构建:
要获知版本信息,请输入
kubectl version.
Downward API 有两种方式可以将 Pod 和 Container 字段呈现给运行中的容器:
这两种呈现 Pod 和 Container 字段的方式统称为 Downward API 。
用 Pod 字段作为环境变量的值 在这个练习中,你将创建一个包含一个容器的 Pod。这是该 Pod 的配置文件:
apiVersion : v1
kind : Pod
metadata :
name : dapi-envars-fieldref
spec :
containers :
- name : test-container
image : k8s.gcr.io/busybox
command : [ "sh" , "-c" ]
args :
- while true; do
echo -en '\n';
printenv MY_NODE_NAME MY_POD_NAME MY_POD_NAMESPACE;
printenv MY_POD_IP MY_POD_SERVICE_ACCOUNT;
sleep 10;
done;
env :
- name : MY_NODE_NAME
valueFrom :
fieldRef :
fieldPath : spec.nodeName
- name : MY_POD_NAME
valueFrom :
fieldRef :
fieldPath : metadata.name
- name : MY_POD_NAMESPACE
valueFrom :
fieldRef :
fieldPath : metadata.namespace
- name : MY_POD_IP
valueFrom :
fieldRef :
fieldPath : status.podIP
- name : MY_POD_SERVICE_ACCOUNT
valueFrom :
fieldRef :
fieldPath : spec.serviceAccountName
restartPolicy : Never
这个配置文件中,你可以看到五个环境变量。env 字段是一个
EnvVars .
对象的数组。
数组中第一个元素指定 MY_NODE_NAME 这个环境变量从 Pod 的 spec.nodeName 字段获取变量值。
同样,其它环境变量也是从 Pod 的字段获取它们的变量值。
说明: 本示例中的字段是 Pod 字段,不是 Pod 中 Container 的字段。
创建Pod:
kubectl apply -f https://k8s.io/examples/pods/inject/dapi-envars-pod.yaml
验证 Pod 中的容器运行正常:
kubectl get pods
查看容器日志:
kubectl logs dapi-envars-fieldref
输出信息显示了所选择的环境变量的值:
minikube
dapi-envars-fieldref
default
172.17.0.4
default
要了解为什么这些值在日志中,请查看配置文件中的command 和 args字段。
当容器启动时,它将五个环境变量的值写入 stdout。每十秒重复执行一次。
接下来,通过打开一个 Shell 进入 Pod 中运行的容器:
kubectl exec -it dapi-envars-fieldref -- sh
在 Shell 中,查看环境变量:
/# printenv
输出信息显示环境变量已经设置为 Pod 字段的值。
MY_POD_SERVICE_ACCOUNT=default
...
MY_POD_NAMESPACE=default
MY_POD_IP=172.17.0.4
...
MY_NODE_NAME=minikube
...
MY_POD_NAME=dapi-envars-fieldref
用 Container 字段作为环境变量的值 前面的练习中,你将 Pod 字段作为环境变量的值。
接下来这个练习中,你将用 Container 字段作为环境变量的值。这里是包含一个容器的 Pod 的配置文件:
apiVersion : v1
kind : Pod
metadata :
name : dapi-envars-resourcefieldref
spec :
containers :
- name : test-container
image : k8s.gcr.io/busybox:1.24
command : [ "sh" , "-c" ]
args :
- while true; do
echo -en '\n';
printenv MY_CPU_REQUEST MY_CPU_LIMIT;
printenv MY_MEM_REQUEST MY_MEM_LIMIT;
sleep 10;
done;
resources :
requests :
memory : "32Mi"
cpu : "125m"
limits :
memory : "64Mi"
cpu : "250m"
env :
- name : MY_CPU_REQUEST
valueFrom :
resourceFieldRef :
containerName : test-container
resource : requests.cpu
- name : MY_CPU_LIMIT
valueFrom :
resourceFieldRef :
containerName : test-container
resource : limits.cpu
- name : MY_MEM_REQUEST
valueFrom :
resourceFieldRef :
containerName : test-container
resource : requests.memory
- name : MY_MEM_LIMIT
valueFrom :
resourceFieldRef :
containerName : test-container
resource : limits.memory
restartPolicy : Never
这个配置文件中,你可以看到四个环境变量。env 字段是一个
EnvVars .
对象的数组。数组中第一个元素指定 MY_CPU_REQUEST 这个环境变量从 Container 的 requests.cpu
字段获取变量值。同样,其它环境变量也是从 Container 的字段获取它们的变量值。
说明: 本例中使用的是 Container 的字段而不是 Pod 的字段。
创建Pod:
kubectl apply -f https://k8s.io/examples/pods/inject/dapi-envars-container.yaml
验证 Pod 中的容器运行正常:
kubectl get pods
查看容器日志:
kubectl logs dapi-envars-resourcefieldref
输出信息显示了所选择的环境变量的值:
1
1
33554432
67108864
接下来 4.6.5 - 通过文件将 Pod 信息呈现给容器 此页面描述 Pod 如何使用 DownwardAPIVolumeFile 把自己的信息呈现给 Pod 中运行的容器。
DownwardAPIVolumeFile 可以呈现 Pod 的字段和容器字段。
准备开始
你必须拥有一个 Kubernetes 的集群,同时你的 Kubernetes 集群必须带有 kubectl 命令行工具。
如果你还没有集群,你可以通过 Minikube 构建一
个你自己的集群,或者你可以使用下面任意一个 Kubernetes 工具构建:
要获知版本信息,请输入
kubectl version.
Downward API 有两种方式可以将 Pod 和 Container 字段呈现给运行中的容器:
这两种呈现 Pod 和 Container 字段的方式都称为 Downward API 。
存储 Pod 字段 在这个练习中,你将创建一个包含一个容器的 Pod。Pod 的配置文件如下:
apiVersion : v1
kind : Pod
metadata :
name : kubernetes-downwardapi-volume-example
labels :
zone : us-est-coast
cluster : test-cluster1
rack : rack-22
annotations :
build : two
builder : john-doe
spec :
containers :
- name : client-container
image : k8s.gcr.io/busybox
command : ["sh" , "-c" ]
args :
- while true; do
if [[ -e /etc/podinfo/labels ]]; then
echo -en '\n\n'; cat /etc/podinfo/labels; fi;
if [[ -e /etc/podinfo/annotations ]]; then
echo -en '\n\n'; cat /etc/podinfo/annotations; fi;
sleep 5;
done;
volumeMounts :
- name : podinfo
mountPath : /etc/podinfo
volumes :
- name : podinfo
downwardAPI :
items :
- path : "labels"
fieldRef :
fieldPath : metadata.labels
- path : "annotations"
fieldRef :
fieldPath : metadata.annotations
在配置文件中,你可以看到 Pod 有一个 downwardAPI 类型的卷,并且挂载到容器中的
/etc/podinfo 目录。
查看 downwardAPI 下面的 items 数组。
每个数组元素都是一个
DownwardAPIVolumeFile
对象。
第一个元素指示 Pod 的 metadata.labels 字段的值保存在名为 labels 的文件中。
第二个元素指示 Pod 的 annotations 字段的值保存在名为 annotations 的文件中。
说明: 本示例中的字段是Pod字段,不是Pod中容器的字段。
创建 Pod:
kubectl apply -f https://k8s.io/examples/pods/inject/dapi-volume.yaml
验证Pod中的容器运行正常:
查看容器的日志:
kubectl logs kubernetes-downwardapi-volume-example
输出显示 labels 和 annotations 文件的内容:
cluster="test-cluster1"
rack="rack-22"
zone="us-est-coast"
build="two"
builder="john-doe"
进入 Pod 中运行的容器,打开一个 Shell:
kubectl exec -it kubernetes-downwardapi-volume-example -- sh
在该 Shell中,查看 labels 文件:
/# cat /etc/podinfo/labels
输出显示 Pod 的所有标签都已写入 labels 文件。
cluster="test-cluster1"
rack="rack-22"
zone="us-est-coast"
同样,查看annotations文件:
/# cat /etc/podinfo/annotations
查看/etc/podinfo目录下的文件:
在输出中可以看到,labels 和 annotations 文件都在一个临时子目录中。
在这个例子,..2982_06_02_21_47_53.299460680。
在 /etc/podinfo 目录中,..data 是一个指向临时子目录
的符号链接。/etc/podinfo 目录中,labels 和 annotations 也是符号链接。
drwxr-xr-x ... Feb 6 21:47 ..2982_06_02_21_47_53.299460680
lrwxrwxrwx ... Feb 6 21:47 ..data -> ..2982_06_02_21_47_53.299460680
lrwxrwxrwx ... Feb 6 21:47 annotations -> ..data/annotations
lrwxrwxrwx ... Feb 6 21:47 labels -> ..data/labels
/etc/podinfo/..2982_06_02_21_47_53.299460680:
total 8
-rw-r--r-- ... Feb 6 21:47 annotations
-rw-r--r-- ... Feb 6 21:47 labels
用符号链接可实现元数据的动态原子性刷新;更新将写入一个新的临时目录,
然后通过使用rename(2)
完成 ..data 符号链接的原子性更新。
说明: 如果容器以
subPath 卷挂载方式来使用
Downward API,则该容器无法收到更新事件。
退出 Shell:
存储容器字段 前面的练习中,你将 Pod 字段保存到 DownwardAPIVolumeFile 中。
接下来这个练习,你将存储 Container 字段。这里是包含一个容器的 Pod 的配置文件:
apiVersion : v1
kind : Pod
metadata :
name : kubernetes-downwardapi-volume-example-2
spec :
containers :
- name : client-container
image : k8s.gcr.io/busybox:1.24
command : ["sh" , "-c" ]
args :
- while true; do
echo -en '\n';
if [[ -e /etc/podinfo/cpu_limit ]]; then
echo -en '\n'; cat /etc/podinfo/cpu_limit; fi;
if [[ -e /etc/podinfo/cpu_request ]]; then
echo -en '\n'; cat /etc/podinfo/cpu_request; fi;
if [[ -e /etc/podinfo/mem_limit ]]; then
echo -en '\n'; cat /etc/podinfo/mem_limit; fi;
if [[ -e /etc/podinfo/mem_request ]]; then
echo -en '\n'; cat /etc/podinfo/mem_request; fi;
sleep 5;
done;
resources :
requests :
memory : "32Mi"
cpu : "125m"
limits :
memory : "64Mi"
cpu : "250m"
volumeMounts :
- name : podinfo
mountPath : /etc/podinfo
volumes :
- name : podinfo
downwardAPI :
items :
- path : "cpu_limit"
resourceFieldRef :
containerName : client-container
resource : limits.cpu
divisor : 1m
- path : "cpu_request"
resourceFieldRef :
containerName : client-container
resource : requests.cpu
divisor : 1m
- path : "mem_limit"
resourceFieldRef :
containerName : client-container
resource : limits.memory
divisor : 1Mi
- path : "mem_request"
resourceFieldRef :
containerName : client-container
resource : requests.memory
divisor : 1Mi
在这个配置文件中,你可以看到 Pod 有一个 downwardAPI 类型的卷,并且挂载到容器的
/etc/podinfo 目录。
查看 downwardAPI 下面的 items 数组。每个数组元素都是一个 DownwardAPIVolumeFile。
第一个元素指定名为 client-container 的容器中 limits.cpu 字段的值应保存在名为
cpu_limit 的文件中。
创建Pod:
kubectl apply -f https://k8s.io/examples/pods/inject/dapi-volume-resources.yaml
打开一个 Shell,进入 Pod 中运行的容器:
kubectl exec -it kubernetes-downwardapi-volume-example-2 -- sh
在 Shell 中,查看 cpu_limit 文件:
/# cat /etc/podinfo/cpu_limit
你可以使用同样的命令查看 cpu_request、mem_limit 和 mem_request 文件.
Downward API 的能力 下面这些信息可以通过环境变量和 downwardAPI 卷提供给容器:
能通过 fieldRef 获得的:metadata.name - Pod 名称metadata.namespace - Pod 名字空间metadata.uid - Pod 的 UIDmetadata.labels['<KEY>'] - Pod 标签 <KEY> 的值 (例如, metadata.labels['mylabel'])metadata.annotations['<KEY>'] - Pod 的注解 <KEY> 的值(例如, metadata.annotations['myannotation']) 能通过 resourceFieldRef 获得的:容器的 CPU 约束值 容器的 CPU 请求值 容器的内存约束值 容器的内存请求值 容器的巨页限制值(前提是启用了 DownwardAPIHugePages 特性门控 ) 容器的巨页请求值(前提是启用了 DownwardAPIHugePages 特性门控 ) 容器的临时存储约束值 容器的临时存储请求值 此外,以下信息可通过 downwardAPI 卷从 fieldRef 获得:
metadata.labels - Pod 的所有标签,以 label-key="escaped-label-value" 格式显示,每行显示一个标签metadata.annotations - Pod 的所有注解,以 annotation-key="escaped-annotation-value"
格式显示,每行显示一个标签以下信息可通过环境变量获得:
status.podIP - 节点 IPspec.serviceAccountName - Pod 服务帐号名称, 版本要求 v1.4.0-alpha.3spec.nodeName - 节点名称, 版本要求 v1.4.0-alpha.3status.hostIP - 节点 IP, 版本要求 v1.7.0-alpha.1说明: 如果容器未指定 CPU 和内存限制,则 Downward API 默认将节点可分配值
视为容器的 CPU 和内存限制。
投射键名到指定路径并且指定文件权限 你可以将键名投射到指定路径并且指定每个文件的访问权限。
更多信息,请参阅Secrets .
Downward API的动机 对于容器来说,有时候拥有自己的信息是很有用的,可避免与 Kubernetes 过度耦合。
Downward API 使得容器使用自己或者集群的信息,而不必通过 Kubernetes 客户端或
API 服务器来获得。
一个例子是有一个现有的应用假定要用一个非常熟悉的环境变量来保存一个唯一标识。
一种可能是给应用增加处理层,但这样是冗余和易出错的,而且它违反了低耦合的目标。
更好的选择是使用 Pod 名称作为标识,把 Pod 名称注入这个环境变量中。
接下来 4.6.6 - 使用 Secret 安全地分发凭证 本文展示如何安全地将敏感数据(如密码和加密密钥)注入到 Pods 中。
准备开始 你必须拥有一个 Kubernetes 的集群,同时你的 Kubernetes 集群必须带有 kubectl 命令行工具。
如果你还没有集群,你可以通过 Minikube 构建一
个你自己的集群,或者你可以使用下面任意一个 Kubernetes 工具构建:
将 secret 数据转换为 base-64 形式 假设用户想要有两条 Secret 数据:用户名 my-app 和密码 39528$vdg7Jb。
首先使用 Base64 编码 将用户名和密码转化为 base-64 形式。
下面是一个使用常用的 base64 程序的示例:
echo -n 'my-app' | base64
echo -n '39528$vdg7Jb' | base64
结果显示 base-64 形式的用户名为 bXktYXBw,
base-64 形式的密码为 Mzk1MjgkdmRnN0pi。
注意: 使用你的操作系统所能信任的本地工具以降低使用外部工具的风险。
创建 Secret 这里是一个配置文件,可以用来创建存有用户名和密码的 Secret:
apiVersion : v1
kind : Secret
metadata :
name : test-secret
data :
username : bXktYXBw
password : Mzk1MjgkdmRnN0pi
创建 Secret:
kubectl apply -f https://k8s.io/examples/pods/inject/secret.yaml
查看 Secret 相关信息:
kubectl get secret test-secret
输出:
NAME TYPE DATA AGE
test-secret Opaque 2 1m
查看 Secret 相关的更多详细信息:
kubectl describe secret test-secret
输出:
Name: test-secret
Namespace: default
Labels: <none>
Annotations: <none>
Type: Opaque
Data
====
password: 13 bytes
username: 7 bytes
直接用 kubectl 创建 Secret 如果你希望略过 Base64 编码的步骤,你也可以使用 kubectl create secret
命令直接创建 Secret。例如:
kubectl create secret generic test-secret --from-literal= 'username=my-app' --from-literal= 'password=39528$vdg7Jb'
这是一种更为方便的方法。
前面展示的详细分解步骤有助于了解究竟发生了什么事情。
创建一个可以通过卷访问 secret 数据的 Pod 这里是一个可以用来创建 pod 的配置文件:
apiVersion : v1
kind : Pod
metadata :
name : secret-test-pod
spec :
containers :
- name : test-container
image : nginx
volumeMounts :
# name must match the volume name below
- name : secret-volume
mountPath : /etc/secret-volume
# The secret data is exposed to Containers in the Pod through a Volume.
volumes :
- name : secret-volume
secret :
secretName : test-secret
创建 Pod:
kubectl create -f secret-pod.yaml
确认 Pod 正在运行:
kubectl get pod secret-test-pod
输出:
NAME READY STATUS RESTARTS AGE
secret-test-pod 1/1 Running 0 42m
获取一个 shell 进入 Pod 中运行的容器:
kubectl exec -it secret-test-pod -- /bin/bash
Secret 数据通过挂载在 /etc/secret-volume 目录下的卷暴露在容器中。
在 shell 中,列举 /etc/secret-volume 目录下的文件:
输出包含两个文件,每个对应一个 Secret 数据条目:
password username
在 Shell 中,显示 username 和 password 文件的内容:
# 在容器中 Shell 运行下面命令
echo " $( cat /etc/secret-volume/username) "
echo " $( cat /etc/secret-volume/password) "
输出为用户名和密码:
使用 Secret 数据定义容器变量 使用来自 Secret 中的数据定义容器变量 定义环境变量为 Secret 中的键值偶对:
kubectl create secret generic backend-user --from-literal= backend-username= 'backend-admin'
创建 Pod:
kubectl create -f https://k8s.io/examples/pods/inject/pod-single-secret-env-variable.yaml
使用来自多个 Secret 的数据定义环境变量 和前面的例子一样,先创建 Secret:
kubectl create secret generic backend-user --from-literal= backend-username= 'backend-admin'
kubectl create secret generic db-user --from-literal= db-username= 'db-admin'
在 Pod 规约中定义环境变量:
apiVersion : v1
kind : Pod
metadata :
name : envvars-multiple-secrets
spec :
containers :
- name : envars-test-container
image : nginx
env :
- name : BACKEND_USERNAME
valueFrom :
secretKeyRef :
name : backend-user
key : backend-username
- name : DB_USERNAME
valueFrom :
secretKeyRef :
name : db-user
key : db-username
创建 Pod:
kubectl create -f https://k8s.io/examples/pods/inject/pod-multiple-secret-env-variable.yaml
将 Secret 中的所有键值偶对定义为环境变量 说明: 此功能在 Kubernetes 1.6 版本之后可用。
创建包含多个键值偶对的 Secret:
kubectl create secret generic test-secret --from-literal= username = 'my-app' --from-literal= password = '39528$vdg7Jb'
创建 Pod:
kubectl create -f https://k8s.io/examples/pods/inject/pod-secret-envFrom.yaml
参考 接下来 4.7 - 运行应用 运行和管理无状态和有状态的应用程序。
4.7.1 - 运行一个单实例有状态应用 本文介绍在 Kubernetes 中如何使用 PersistentVolume 和 Deployment 运行一个单实例有状态应用。该应用是 MySQL.
教程目标 在你的环境中创建一个引用磁盘的 PersistentVolume 创建一个 MySQL Deployment. 在集群内以一个已知的 DNS 名称将 MySQL 暴露给其他 Pod 准备开始 部署 MySQL 你可以通过创建一个 Kubernetes Deployment 并使用 PersistentVolumeClaim 将其连接到
某已有的 PV 卷来运行一个有状态的应用。
例如,这里的 YAML 描述的是一个运行 MySQL 的 Deployment,其中引用了 PVC 申领。
文件为 /var/lib/mysql 定义了加载卷,并创建了一个 PVC 申领,寻找一个 20G 大小的卷。
该申领可以通过现有的满足需求的卷来满足,也可以通过动态供应卷的机制来满足。
注意:在配置的 YAML 文件中定义密码的做法是不安全的。具体安全解决方案请参考
Kubernetes Secrets .
apiVersion : v1
kind : Service
metadata :
name : mysql
spec :
ports :
- port : 3306
selector :
app : mysql
clusterIP : None
---
apiVersion : apps/v1
kind : Deployment
metadata :
name : mysql
spec :
selector :
matchLabels :
app : mysql
strategy :
type : Recreate
template :
metadata :
labels :
app : mysql
spec :
containers :
- image : mysql:5.6
name : mysql
env :
# Use secret in real usage
- name : MYSQL_ROOT_PASSWORD
value : password
ports :
- containerPort : 3306
name : mysql
volumeMounts :
- name : mysql-persistent-storage
mountPath : /var/lib/mysql
volumes :
- name : mysql-persistent-storage
persistentVolumeClaim :
claimName : mysql-pv-claim
apiVersion : v1
kind : PersistentVolume
metadata :
name : mysql-pv-volume
labels :
type : local
spec :
storageClassName : manual
capacity :
storage : 20Gi
accessModes :
- ReadWriteOnce
hostPath :
path : "/mnt/data"
---
apiVersion : v1
kind : PersistentVolumeClaim
metadata :
name : mysql-pv-claim
spec :
storageClassName : manual
accessModes :
- ReadWriteOnce
resources :
requests :
storage : 20Gi
部署 YAML 文件中定义的 PV 和 PVC:
kubectl apply -f https://k8s.io/examples/application/mysql/mysql-pv.yaml
部署 YAML 文件中定义的 Deployment:
kubectl apply -f https://k8s.io/examples/application/mysql/mysql-deployment.yaml
展示 Deployment 相关信息:
kubectl describe deployment mysql
Name: mysql
Namespace: default
CreationTimestamp: Tue, 01 Nov 2016 11:18:45 -0700
Labels: app=mysql
Annotations: deployment.kubernetes.io/revision=1
Selector: app=mysql
Replicas: 1 desired | 1 updated | 1 total | 0 available | 1 unavailable
StrategyType: Recreate
MinReadySeconds: 0
Pod Template:
Labels: app=mysql
Containers:
mysql:
Image: mysql:5.6
Port: 3306/TCP
Environment:
MYSQL_ROOT_PASSWORD: password
Mounts:
/var/lib/mysql from mysql-persistent-storage (rw)
Volumes:
mysql-persistent-storage:
Type: PersistentVolumeClaim (a reference to a PersistentVolumeClaim in the same namespace)
ClaimName: mysql-pv-claim
ReadOnly: false
Conditions:
Type Status Reason
---- ------ ------
Available False MinimumReplicasUnavailable
Progressing True ReplicaSetUpdated
OldReplicaSets: <none>
NewReplicaSet: mysql-63082529 (1/1 replicas created)
Events:
FirstSeen LastSeen Count From SubobjectPath Type Reason Message
--------- -------- ----- ---- ------------- -------- ------ -------
33s 33s 1 {deployment-controller } Normal ScalingReplicaSet Scaled up replica set mysql-63082529 to 1
列举出 Deployment 创建的 pods:
kubectl get pods -l app = mysql
NAME READY STATUS RESTARTS AGE
mysql-63082529-2z3ki 1/1 Running 0 3m
查看 PersistentVolumeClaim:
kubectl describe pvc mysql-pv-claim
Name: mysql-pv-claim
Namespace: default
StorageClass:
Status: Bound
Volume: mysql-pv-volume
Labels: <none>
Annotations: pv.kubernetes.io/bind-completed=yes
pv.kubernetes.io/bound-by-controller=yes
Capacity: 20Gi
Access Modes: RWO
Events: <none>
访问 MySQL 实例 前面 YAML 文件中创建了一个允许集群内其他 Pod 访问的数据库服务。该服务中选项
clusterIP: None 让服务 DNS 名称直接解析为 Pod 的 IP 地址。
当在一个服务下只有一个 Pod 并且不打算增加 Pod 的数量这是最好的.
运行 MySQL 客户端以连接到服务器:
kubectl run -it --rm --image=mysql:5.6 --restart=Never mysql-client -- mysql -h mysql -ppassword
此命令在集群内创建一个新的 Pod 并运行 MySQL 客户端,并通过 Service 连接到服务器。
如果连接成功,你就知道有状态的 MySQL 数据库正处于运行状态。
Waiting for pod default/mysql-client-274442439-zyp6i to be running, status is Pending, pod ready: false
If you don't see a command prompt, try pressing enter.
mysql>
更新 Deployment 中镜像或其他部分同往常一样可以通过 kubectl apply 命令更新。
以下是特定于有状态应用的一些注意事项:
不要对应用进行规模扩缩。这里的设置仅适用于单实例应用。下层的 PersistentVolume
仅只能挂载到一个 Pod 上。对于集群级有状态应用,请参考
StatefulSet 文档 . 在 Deployment 的 YAML 文件中使用 strategy: type: Recreate。
该选项指示 Kubernetes 不 使用滚动升级。滚动升级无法工作,因为这里一次不能
运行多个 Pod。在使用更新的配置文件创建新的 Pod 前,Recreate 策略将
保证先停止第一个 Pod。 删除 Deployment 通过名称删除部署的对象:
kubectl delete deployment,svc mysql
kubectl delete pvc mysql-pv-claim
kubectl delete pv mysql-pv-volume
如果通过手动的方式供应 PersistentVolume, 那么也需要手动删除它以释放下层资源。
如果是用动态供应方式创建的 PersistentVolume,在删除 PersistentVolumeClaim 后
PersistentVolume 将被自动删除。
一些存储服务(比如 EBS 和 PD)也会在 PersistentVolume 被删除时自动回收下层资源。
接下来 4.7.2 - 运行一个有状态的应用程序 本页展示如何使用 StatefulSet
控制器运行一个有状态的应用程序。此例是多副本的 MySQL 数据库。
示例应用的拓扑结构有一个主服务器和多个副本,使用异步的基于行(Row-Based)
的数据复制。
说明: 这不是生产环境下配置 。
尤其注意,MySQL 设置都使用的是不安全的默认值,这是因为我们想把重点放在 Kubernetes
中运行有状态应用程序的一般模式上。
准备开始
你必须拥有一个 Kubernetes 的集群,同时你的 Kubernetes 集群必须带有 kubectl 命令行工具。
如果你还没有集群,你可以通过 Minikube 构建一
个你自己的集群,或者你可以使用下面任意一个 Kubernetes 工具构建:
要获知版本信息,请输入
kubectl version.
您需要有一个带有默认StorageClass 的动态持续卷供应程序,或者自己静态的提供持久卷 来满足这里使用的持久卷请求 。
教程目标 使用 StatefulSet 控制器部署多副本 MySQL 拓扑架构。 发送 MySQL 客户端请求 观察对宕机的抵抗力 扩缩 StatefulSet 的规模 部署 MySQL MySQL 示例部署包含一个 ConfigMap、两个 Service 与一个 StatefulSet。
ConfigMap 使用以下的 YAML 配置文件创建 ConfigMap :
apiVersion : v1
kind : ConfigMap
metadata :
name : mysql
labels :
app : mysql
data :
master.cnf : |
# Apply this config only on the master.
[mysqld]
log-bin
slave.cnf : |
# Apply this config only on slaves.
[mysqld]
super-read-only
kubectl apply -f https://k8s.io/examples/application/mysql/mysql-configmap.yaml
这个 ConfigMap 提供 my.cnf 覆盖设置,使你可以独立控制 MySQL 主服务器和从服务器的配置。
在这里,你希望主服务器能够将复制日志提供给副本服务器,并且希望副本服务器拒绝任何不是通过
复制进行的写操作。
ConfigMap 本身没有什么特别之处,因而也不会出现不同部分应用于不同的 Pod 的情况。
每个 Pod 都会在初始化时基于 StatefulSet 控制器提供的信息决定要查看的部分。
服务 使用以下 YAML 配置文件创建服务:
# Headless service for stable DNS entries of StatefulSet members.
apiVersion : v1
kind : Service
metadata :
name : mysql
labels :
app : mysql
spec :
ports :
- name : mysql
port : 3306
clusterIP : None
selector :
app : mysql
---
# Client service for connecting to any MySQL instance for reads.
# For writes, you must instead connect to the master: mysql-0.mysql.
apiVersion : v1
kind : Service
metadata :
name : mysql-read
labels :
app : mysql
spec :
ports :
- name : mysql
port : 3306
selector :
app : mysql
kubectl apply -f https://k8s.io/examples/application/mysql/mysql-services.yaml
这个无头服务给 StatefulSet 控制器为集合中每个 Pod 创建的 DNS 条目提供了一个宿主。
因为服务名为 mysql,所以可以通过在同一 Kubernetes 集群和名字中的任何其他 Pod
内解析 <Pod 名称>.mysql 来访问 Pod。
客户端服务称为 mysql-read,是一种常规服务,具有其自己的集群 IP。
该集群 IP 在报告就绪的所有MySQL Pod 之间分配连接。
可能的端点集合包括 MySQL 主节点和所有副本节点。
请注意,只有读查询才能使用负载平衡的客户端服务。
因为只有一个 MySQL 主服务器,所以客户端应直接连接到 MySQL 主服务器 Pod
(通过其在无头服务中的 DNS 条目)以执行写入操作。
StatefulSet 最后,使用以下 YAML 配置文件创建 StatefulSet:
apiVersion : apps/v1
kind : StatefulSet
metadata :
name : mysql
spec :
selector :
matchLabels :
app : mysql
serviceName : mysql
replicas : 3
template :
metadata :
labels :
app : mysql
spec :
initContainers :
- name : init-mysql
image : mysql:5.7
command :
- bash
- "-c"
- |
set -ex
# Generate mysql server-id from pod ordinal index.
[[ `hostname` =~ -([0-9]+)$ ]] || exit 1
ordinal=${BASH_REMATCH[1]}
echo [mysqld] > /mnt/conf.d/server-id.cnf
# Add an offset to avoid reserved server-id=0 value.
echo server-id=$((100 + $ordinal)) >> /mnt/conf.d/server-id.cnf
# Copy appropriate conf.d files from config-map to emptyDir.
if [[ $ordinal -eq 0 ]]; then
cp /mnt/config-map/master.cnf /mnt/conf.d/
else
cp /mnt/config-map/slave.cnf /mnt/conf.d/
fi
volumeMounts :
- name : conf
mountPath : /mnt/conf.d
- name : config-map
mountPath : /mnt/config-map
- name : clone-mysql
image : gcr.io/google-samples/xtrabackup:1.0
command :
- bash
- "-c"
- |
set -ex
# Skip the clone if data already exists.
[[ -d /var/lib/mysql/mysql ]] && exit 0
# Skip the clone on master (ordinal index 0).
[[ `hostname` =~ -([0-9]+)$ ]] || exit 1
ordinal=${BASH_REMATCH[1]}
[[ $ordinal -eq 0 ]] && exit 0
# Clone data from previous peer.
ncat --recv-only mysql-$(($ordinal-1)).mysql 3307 | xbstream -x -C /var/lib/mysql
# Prepare the backup.
xtrabackup --prepare --target-dir=/var/lib/mysql
volumeMounts :
- name : data
mountPath : /var/lib/mysql
subPath : mysql
- name : conf
mountPath : /etc/mysql/conf.d
containers :
- name : mysql
image : mysql:5.7
env :
- name : MYSQL_ALLOW_EMPTY_PASSWORD
value : "1"
ports :
- name : mysql
containerPort : 3306
volumeMounts :
- name : data
mountPath : /var/lib/mysql
subPath : mysql
- name : conf
mountPath : /etc/mysql/conf.d
resources :
requests :
cpu : 500m
memory : 1Gi
livenessProbe :
exec :
command : ["mysqladmin" , "ping" ]
initialDelaySeconds : 30
periodSeconds : 10
timeoutSeconds : 5
readinessProbe :
exec :
# Check we can execute queries over TCP (skip-networking is off).
command : ["mysql" , "-h" , "127.0.0.1" , "-e" , "SELECT 1" ]
initialDelaySeconds : 5
periodSeconds : 2
timeoutSeconds : 1
- name : xtrabackup
image : gcr.io/google-samples/xtrabackup:1.0
ports :
- name : xtrabackup
containerPort : 3307
command :
- bash
- "-c"
- |
set -ex
cd /var/lib/mysql
# Determine binlog position of cloned data, if any.
if [[ -f xtrabackup_slave_info && "x$(<xtrabackup_slave_info)" != "x" ]]; then
# XtraBackup already generated a partial "CHANGE MASTER TO" query
# because we're cloning from an existing slave. (Need to remove the tailing semicolon!)
cat xtrabackup_slave_info | sed -E 's/;$//g' > change_master_to.sql.in
# Ignore xtrabackup_binlog_info in this case (it's useless).
rm -f xtrabackup_slave_info xtrabackup_binlog_info
elif [[ -f xtrabackup_binlog_info ]]; then
# We're cloning directly from master. Parse binlog position.
[[ `cat xtrabackup_binlog_info` =~ ^(.*?)[[:space:]]+(.*?)$ ]] || exit 1
rm -f xtrabackup_binlog_info xtrabackup_slave_info
echo "CHANGE MASTER TO MASTER_LOG_FILE='${BASH_REMATCH[1]}',\
MASTER_LOG_POS=${BASH_REMATCH[2]}" > change_master_to.sql.in
fi
# Check if we need to complete a clone by starting replication.
if [[ -f change_master_to.sql.in ]]; then
echo "Waiting for mysqld to be ready (accepting connections)"
until mysql -h 127.0.0.1 -e "SELECT 1"; do sleep 1; done
echo "Initializing replication from clone position"
mysql -h 127.0.0.1 \
-e "$(<change_master_to.sql.in), \
MASTER_HOST='mysql-0.mysql', \
MASTER_USER='root', \
MASTER_PASSWORD='', \
MASTER_CONNECT_RETRY=10; \
START SLAVE;" || exit 1
# In case of container restart, attempt this at-most-once.
mv change_master_to.sql.in change_master_to.sql.orig
fi
# Start a server to send backups when requested by peers.
exec ncat --listen --keep-open --send-only --max-conns=1 3307 -c \
"xtrabackup --backup --slave-info --stream=xbstream --host=127.0.0.1 --user=root"
volumeMounts :
- name : data
mountPath : /var/lib/mysql
subPath : mysql
- name : conf
mountPath : /etc/mysql/conf.d
resources :
requests :
cpu : 100m
memory : 100Mi
volumes :
- name : conf
emptyDir : {}
- name : config-map
configMap :
name : mysql
volumeClaimTemplates :
- metadata :
name : data
spec :
accessModes : ["ReadWriteOnce" ]
resources :
requests :
storage : 10Gi
kubectl apply -f https://k8s.io/examples/application/mysql/mysql-statefulset.yaml
你可以通过运行以下命令查看启动进度:
kubectl get pods -l app = mysql --watch
一段时间后,你应该看到所有 3 个 Pod 进入 Running 状态:
NAME READY STATUS RESTARTS AGE
mysql-0 2/2 Running 0 2m
mysql-1 2/2 Running 0 1m
mysql-2 2/2 Running 0 1m
输入 Ctrl+C 结束 watch 操作。
如果你看不到任何进度,确保已启用前提条件
中提到的动态 PersistentVolume 预配器。
此清单使用多种技术来管理作为 StatefulSet 的一部分的有状态 Pod。
下一节重点介绍其中的一些技巧,以解释 StatefulSet 创建 Pod 时发生的状况。
了解有状态的 Pod 初始化 StatefulSet 控制器按序数索引顺序地每次启动一个 Pod。
它一直等到每个 Pod 报告就绪才再启动下一个 Pod。
此外,控制器为每个 Pod 分配一个唯一、稳定的名称,形如 <statefulset 名称>-<序数索引>,
其结果是 Pods 名为 mysql-0、mysql-1 和 mysql-2。
上述 StatefulSet 清单中的 Pod 模板利用这些属性来执行 MySQL 副本的有序启动。
生成配置 在启动 Pod 规约中的任何容器之前,Pod 首先按顺序运行所有的
Init 容器 。
第一个名为 init-mysql 的 Init 容器根据序号索引生成特殊的 MySQL 配置文件。
该脚本通过从 Pod 名称的末尾提取索引来确定自己的序号索引,而 Pod 名称由 hostname 命令返回。
然后将序数(带有数字偏移量以避免保留值)保存到 MySQL conf.d 目录中的文件 server-id.cnf。
这一操作将 StatefulSet 所提供的唯一、稳定的标识转换为 MySQL 服务器的 ID,
而这些 ID 也是需要唯一性、稳定性保证的。
通过将内容复制到 conf.d 中,init-mysql 容器中的脚本也可以应用 ConfigMap 中的 primary.cnf 或 replica.cnf。
由于示例部署结构由单个 MySQL 主节点和任意数量的副本节点组成,
因此脚本仅将序数 0 指定为主节点,而将其他所有节点指定为副本节点。
与 StatefulSet 控制器的
部署顺序保证
相结合,
可以确保 MySQL 主服务器在创建副本服务器之前已准备就绪,以便它们可以开始复制。
克隆现有数据 通常,当新 Pod 作为副本节点加入集合时,必须假定 MySQL 主节点可能已经有数据。
还必须假设复制日志可能不会一直追溯到时间的开始。
这些保守的假设是允许正在运行的 StatefulSet 随时间扩大和缩小而不是固定在其初始大小的关键。
第二个名为 clone-mysql 的 Init 容器,第一次在带有空 PersistentVolume 的副本 Pod
上启动时,会在从属 Pod 上执行克隆操作。
这意味着它将从另一个运行中的 Pod 复制所有现有数据,使此其本地状态足够一致,
从而可以开始从主服务器复制。
MySQL 本身不提供执行此操作的机制,因此本示例使用了一种流行的开源工具 Percona XtraBackup。
在克隆期间,源 MySQL 服务器性能可能会受到影响。
为了最大程度地减少对 MySQL 主服务器的影响,该脚本指示每个 Pod 从序号较低的 Pod 中克隆。
可以这样做的原因是 StatefulSet 控制器始终确保在启动 Pod N + 1 之前 Pod N 已准备就绪。
开始复制 Init 容器成功完成后,应用容器将运行。
MySQL Pod 由运行实际 mysqld 服务的 mysql 容器和充当
辅助工具
的 xtrabackup 容器组成。
xtrabackup sidecar 容器查看克隆的数据文件,并确定是否有必要在副本服务器上初始化 MySQL 复制。
如果是这样,它将等待 mysqld 准备就绪,然后使用从 XtraBackup 克隆文件中提取的复制参数
执行 CHANGE MASTER TO 和 START SLAVE 命令。
一旦副本服务器开始复制后,它会记住其 MySQL 主服务器,并且如果服务器重新启动或
连接中断也会自动重新连接。
另外,因为副本服务器会以其稳定的 DNS 名称查找主服务器(mysql-0.mysql),
即使由于重新调度而获得新的 Pod IP,它们也会自动找到主服务器。
最后,开始复制后,xtrabackup 容器监听来自其他 Pod 的连接,处理其数据克隆请求。
如果 StatefulSet 扩大规模,或者下一个 Pod 失去其 PersistentVolumeClaim 并需要重新克隆,
则此服务器将无限期保持运行。
发送客户端请求 你可以通过运行带有 mysql:5.7 镜像的临时容器并运行 mysql 客户端二进制文件,
将测试查询发送到 MySQL 主服务器(主机名 mysql-0.mysql)。
kubectl run mysql-client --image= mysql:5.7 -i --rm --restart= Never --\
mysql -h mysql-0.mysql <<EOF
CREATE DATABASE test;
CREATE TABLE test.messages (message VARCHAR(250));
INSERT INTO test.messages VALUES ('hello');
EOF
使用主机名 mysql-read 将测试查询发送到任何报告为就绪的服务器:
kubectl run mysql-client --image= mysql:5.7 -i -t --rm --restart= Never --\
mysql -h mysql-read -e "SELECT * FROM test.messages"
你应该获得如下输出:
Waiting for pod default/mysql-client to be running, status is Pending, pod ready: false
+---------+
| message |
+---------+
| hello |
+---------+
pod "mysql-client" deleted
为了演示 mysql-read 服务在服务器之间分配连接,你可以在循环中运行 SELECT @@server_id:
kubectl run mysql-client-loop --image= mysql:5.7 -i -t --rm --restart= Never --\
bash -ic "while sleep 1; do mysql -h mysql-read -e 'SELECT @@server_id,NOW()'; done"
你应该看到报告的 @@server_id 发生随机变化,因为每次尝试连接时都可能选择了不同的端点:
+-------------+---------------------+
| @@server_id | NOW() |
+-------------+---------------------+
| 100 | 2006-01-02 15:04:05 |
+-------------+---------------------+
+-------------+---------------------+
| @@server_id | NOW() |
+-------------+---------------------+
| 102 | 2006-01-02 15:04:06 |
+-------------+---------------------+
+-------------+---------------------+
| @@server_id | NOW() |
+-------------+---------------------+
| 101 | 2006-01-02 15:04:07 |
+-------------+---------------------+
要停止循环时可以按 Ctrl+C ,但是让它在另一个窗口中运行非常有用,
这样你就可以看到以下步骤的效果。
模拟 Pod 和 Node 的宕机时间 为了证明从副本节点缓存而不是单个服务器读取数据的可用性提高,请在使 Pod 退出 Ready
状态时,保持上述 SELECT @@server_id 循环一直运行。
破坏就绪态探测 mysql 容器的
就绪态探测
运行命令 mysql -h 127.0.0.1 -e 'SELECT 1',以确保服务器已启动并能够执行查询。
迫使就绪态探测失败的一种方法就是中止该命令:
kubectl exec mysql-2 -c mysql -- mv /usr/bin/mysql /usr/bin/mysql.off
此命令会进入 Pod mysql-2 的实际容器文件系统,重命名 mysql 命令,导致就绪态探测无法找到它。
几秒钟后, Pod 会报告其中一个容器未就绪。你可以通过运行以下命令进行检查:
在 READY 列中查找 1/2 :
NAME READY STATUS RESTARTS AGE
mysql-2 1/2 Running 0 3m
此时,你应该会看到 SELECT @@server_id 循环继续运行,尽管它不再报告 102。
回想一下,init-mysql 脚本将 server-id 定义为 100 + $ordinal,
因此服务器 ID 102 对应于 Pod mysql-2。
现在修复 Pod,几秒钟后它应该重新出现在循环输出中:
kubectl exec mysql-2 -c mysql -- mv /usr/bin/mysql.off /usr/bin/mysql
删除 Pods 如果删除了 Pod,则 StatefulSet 还会重新创建 Pod,类似于 ReplicaSet 对无状态 Pod 所做的操作。
kubectl delete pod mysql-2
StatefulSet 控制器注意到不再存在 mysql-2 Pod,于是创建一个具有相同名称并链接到相同
PersistentVolumeClaim 的新 Pod。
你应该看到服务器 ID 102 从循环输出中消失了一段时间,然后又自行出现。
腾空节点 如果你的 Kubernetes 集群具有多个节点,则可以通过发出以下
drain
命令来模拟节点停机(就好像节点在被升级)。
首先确定 MySQL Pod 之一在哪个节点上:
kubectl get pod mysql-2 -o wide
节点名称应显示在最后一列中:
NAME READY STATUS RESTARTS AGE IP NODE
mysql-2 2/2 Running 0 15m 10.244.5.27 kubernetes-node-9l2t
然后通过运行以下命令腾空节点,该命令将其保护起来,以使新的 Pod 不能调度到该节点,
然后逐出所有现有的 Pod。将 <节点名称> 替换为在上一步中找到的节点名称。
这可能会影响节点上的其他应用程序,因此最好 仅在测试集群中执行此操作 。
kubectl drain <节点名称> --force --delete-local-data --ignore-daemonsets
现在,你可以看到 Pod 被重新调度到其他节点上:
kubectl get pod mysql-2 -o wide --watch
它看起来应该像这样:
NAME READY STATUS RESTARTS AGE IP NODE
mysql-2 2/2 Terminating 0 15m 10.244.1.56 kubernetes-node-9l2t
[...]
mysql-2 0/2 Pending 0 0s <none> kubernetes-node-fjlm
mysql-2 0/2 Init:0/2 0 0s <none> kubernetes-node-fjlm
mysql-2 0/2 Init:1/2 0 20s 10.244.5.32 kubernetes-node-fjlm
mysql-2 0/2 PodInitializing 0 21s 10.244.5.32 kubernetes-node-fjlm
mysql-2 1/2 Running 0 22s 10.244.5.32 kubernetes-node-fjlm
mysql-2 2/2 Running 0 30s 10.244.5.32 kubernetes-node-fjlm
再次,你应该看到服务器 ID 102 从 SELECT @@server_id 循环输出
中消失一段时间,然后自行出现。
现在去掉节点保护(Uncordon),使其恢复为正常模式:
扩展副本节点数量 使用 MySQL 复制,你可以通过添加副本节点来扩展读取查询的能力。
使用 StatefulSet,你可以使用单个命令执行此操作:
kubectl scale statefulset mysql --replicas= 5
查看新的 Pod 的运行情况:
kubectl get pods -l app = mysql --watch
一旦 Pod 启动,你应该看到服务器 IDs 103 和 104 开始出现在 SELECT @@server_id 循环输出中。
你还可以验证这些新服务器在存在之前已添加了数据:
kubectl run mysql-client --image= mysql:5.7 -i -t --rm --restart= Never --\
mysql -h mysql-3.mysql -e "SELECT * FROM test.messages"
Waiting for pod default/mysql-client to be running, status is Pending, pod ready: false
+---------+
| message |
+---------+
| hello |
+---------+
pod "mysql-client" deleted
向下缩容操作也是很平滑的:
kubectl scale statefulset mysql --replicas= 3
但是请注意,按比例扩大会自动创建新的 PersistentVolumeClaims,而按比例缩小不会自动删除这些 PVC。
这使你可以选择保留那些初始化的 PVC,以更快地进行缩放,或者在删除它们之前提取数据。
你可以通过运行以下命令查看此信息:
kubectl get pvc -l app = mysql
这表明,尽管将 StatefulSet 缩小为3,所有5个 PVC 仍然存在:
NAME STATUS VOLUME CAPACITY ACCESSMODES AGE
data-mysql-0 Bound pvc-8acbf5dc-b103-11e6-93fa-42010a800002 10Gi RWO 20m
data-mysql-1 Bound pvc-8ad39820-b103-11e6-93fa-42010a800002 10Gi RWO 20m
data-mysql-2 Bound pvc-8ad69a6d-b103-11e6-93fa-42010a800002 10Gi RWO 20m
data-mysql-3 Bound pvc-50043c45-b1c5-11e6-93fa-42010a800002 10Gi RWO 2m
data-mysql-4 Bound pvc-500a9957-b1c5-11e6-93fa-42010a800002 10Gi RWO 2m
如果你不打算重复使用多余的 PVC,则可以删除它们:
kubectl delete pvc data-mysql-3
kubectl delete pvc data-mysql-4
清理现场 通过在终端上按 Ctrl+C 取消 SELECT @@server_id 循环,或从另一个终端运行以下命令:
kubectl delete pod mysql-client-loop --now
删除 StatefulSet。这也会开始终止 Pod。
kubectl delete statefulset mysql
验证 Pod 消失。他们可能需要一些时间才能完成终止。
kubectl get pods -l app = mysql
当上述命令返回如下内容时,你就知道 Pod 已终止:
No resources found.
删除 ConfigMap、Services 和 PersistentVolumeClaims。
kubectl delete configmap,service,pvc -l app = mysql
如果你手动供应 PersistentVolume,则还需要手动删除它们,并释放下层资源。
如果你使用了动态预配器,当得知你删除 PersistentVolumeClaims 时,它将自动删除 PersistentVolumes。
一些动态预配器(例如用于 EBS 和 PD 的预配器)也会在删除 PersistentVolumes 时释放下层资源。 接下来 4.7.3 - 删除 StatefulSet 本任务展示如何删除 StatefulSet。
准备开始 本任务假设在你的集群上已经运行了由 StatefulSet 创建的应用。 删除 StatefulSet 你可以像删除 Kubernetes 中的其他资源一样删除 StatefulSet:使用 kubectl delete 命令,并按文件或者名字指定 StatefulSet。
kubectl delete -f <file.yaml>
kubectl delete statefulsets <statefulset 名称>
删除 StatefulSet 之后,你可能需要单独删除关联的无头服务。
kubectl delete service <服务名称>
通过 kubectl 删除 StatefulSet 会将其缩容为 0,因此删除属于它的所有 Pod。
如果你只想删除 StatefulSet 而不删除 Pod,使用 --cascade=false。
kubectl delete -f <file.yaml> --cascade= false
通过将 --cascade=false 传递给 kubectl delete,在删除 StatefulSet 对象之后,
StatefulSet 管理的 Pod 会被保留下来。如果 Pod 具有标签 app=myapp,则可以按照
如下方式删除它们:
kubectl delete pods -l app = myapp
持久卷 删除 StatefulSet 管理的 Pod 并不会删除关联的卷。这是为了确保你有机会在删除卷之前从卷中复制数据。
在 Pod 离开终止状态
后删除 PVC 可能会触发删除背后的 PV 持久卷,具体取决于存储类和回收策略。
永远不要假定在 PVC 删除后仍然能够访问卷。
说明: 删除 PVC 时要谨慎,因为这可能会导致数据丢失。
完全删除 StatefulSet 要简单地删除 StatefulSet 中的所有内容,包括关联的 pods,你可能需要运行一系列类似于以下内容的命令:
grace = $( kubectl get pods <stateful-set-pod> --template '{{.spec.terminationGracePeriodSeconds}}' )
kubectl delete statefulset -l app = myapp
sleep $grace
kubectl delete pvc -l app = myapp
在上面的例子中,Pod 的标签为 app=myapp;适当地替换你自己的标签。
强制删除 StatefulSet 的 Pod 如果你发现 StatefulSet 的某些 Pod 长时间处于 'Terminating' 或者 'Unknown' 状态,
则可能需要手动干预以强制从 API 服务器中删除这些 Pod。
这是一项有点危险的任务。详细信息请阅读
删除 StatefulSet 类型的 Pods 。
接下来 进一步了解强制删除 StatefulSet 的 Pods 。
4.7.4 - 强制删除 StatefulSet 类型的 Pods 本文介绍了如何删除 StatefulSet
管理的 Pods,并且解释了这样操作时需要记住的注意事项。
准备开始 这是一项相当高级的任务,并且可能会违反 StatefulSet 固有的某些属性。 继续任务之前,请熟悉下面列举的注意事项。 StatefulSet 注意事项 在 StatefulSet 的正常操作中,永远不 需要强制删除 StatefulSet 管理的 Pod。
StatefulSet 控制器 负责创建、
扩缩和删除 StatefulSet 管理的 Pods。它尝试确保指定数量的从序数 0 到 N-1 的 Pod
处于活跃状态并准备就绪。StatefulSet 确保在任何时候,集群中最多只有一个具有给定标识的 Pod。
这就是所谓的由 StatefulSet 提供的*最多一个(At Most One)*的语义。
应谨慎进行手动强制删除操作,因为它可能会违反 StatefulSet 固有的至多一个的语义。
StatefulSets 可用于运行分布式和集群级的应用,这些应用需要稳定的网络标识和可靠的存储。
这些应用通常配置为具有固定标识固定数量的成员集合。
具有相同身份的多个成员可能是灾难性的,并且可能导致数据丢失 (例如:票选系统中的脑裂场景)。
删除 Pods 你可以使用下面的命令执行体面地删除 Pod:
kubectl delete pods <pod>
为了让上面操作能够体面地终止 Pod,Pod 一定不能 设置 pod.Spec.TerminationGracePeriodSeconds 为 0。
将 pod.Spec.TerminationGracePeriodSeconds 设置为 0s 的做法是不安全的,强烈建议 StatefulSet 类型的
Pod 不要使用。体面删除是安全的,并且会在 kubelet 从 API 服务器中删除资源名称之前确保
体面地结束 pod 。
Kubernetes(1.5 版本或者更新版本)不会因为一个节点无法访问而删除 Pod。
在无法访问的节点上运行的 Pod 在
超时
后会进入'Terminating' 或者 'Unknown' 状态。
当用户尝试体面地删除无法访问的节点上的 Pod 时 Pod 也可能会进入这些状态。
从 API 服务器上删除处于这些状态 Pod 的仅有可行方法如下:
删除 Node 对象(要么你来删除, 要么节点控制器
来删除) 无响应节点上的 kubelet 开始响应,杀死 Pod 并从 API 服务器上移除 Pod 对象 用户强制删除 pod 推荐使用第一种或者第二种方法。如果确认节点已经不可用了 (比如,永久断开网络、断电等),
则应删除 Node 对象。
如果节点遇到网裂问题,请尝试解决该问题或者等待其解决。
当网裂愈合时,kubelet 将完成 Pod 的删除并从 API 服务器上释放其名字。
通常,Pod 一旦不在节点上运行,或者管理员删除了节点,系统就会完成其删除动作。
你也可以通过强制删除 Pod 来绕过这一机制。
强制删除 强制删除不会 等待来自 kubelet 对 Pod 已终止的确认消息。
无论强制删除是否成功杀死了 Pod,它都会立即从 API 服务器中释放该名字。
这将让 StatefulSet 控制器创建一个具有相同标识的替身 Pod;因而可能导致正在运行 Pod 的重复,
并且如果所述 Pod 仍然可以与 StatefulSet 的成员通信,则将违反 StatefulSet 所要保证的
最多一个的语义。
当你强制删除 StatefulSet 类型的 Pod 时,你要确保有问题的 Pod 不会再和 StatefulSet 管理的其他
Pod 通信并且可以安全地释放其名字以便创建替代 Pod。
如果要使用 kubectl 1.5 以上版本强制删除 Pod,请执行下面命令:
kubectl delete pods <pod> --grace-period= 0 --force
如果你使用 kubectl 的 1.4 以下版本,则应省略 --force 选项:
kubectl delete pods <pod> --grace-period= 0
如果在这些命令后 Pod 仍处于 Unknown 状态,请使用以下命令从集群中删除 Pod:
kubectl patch pod <pod> -p '{"metadata":{"finalizers":null}}'
请始终谨慎地执行强制删除 StatefulSet 类型的 pods,并完全了解所涉及地风险。
接下来 进一步了解调试 StatefulSet 。
4.7.5 - Pod 水平自动扩缩 Pod 水平自动扩缩(Horizontal Pod Autoscaler)
可以基于 CPU 利用率自动扩缩 ReplicationController、Deployment、ReplicaSet 和 StatefulSet 中的 Pod 数量。
除了 CPU 利用率,也可以基于其他应程序提供的自定义度量指标
来执行自动扩缩。
Pod 自动扩缩不适用于无法扩缩的对象,比如 DaemonSet。
Pod 水平自动扩缩特性由 Kubernetes API 资源和控制器实现。资源决定了控制器的行为。
控制器会周期性的调整副本控制器或 Deployment 中的副本数量,以使得 Pod 的平均 CPU
利用率与用户所设定的目标值匹配。
Pod 水平自动扩缩工作机制
Pod 水平自动扩缩器的实现是一个控制回路,由控制器管理器的 --horizontal-pod-autoscaler-sync-period 参数指定周期(默认值为 15 秒)。
每个周期内,控制器管理器根据每个 HorizontalPodAutoscaler 定义中指定的指标查询资源利用率。
控制器管理器可以从资源度量指标 API(按 Pod 统计的资源用量)和自定义度量指标 API(其他指标)获取度量值。
对于按 Pod 统计的资源指标(如 CPU),控制器从资源指标 API 中获取每一个
HorizontalPodAutoscaler 指定的 Pod 的度量值,如果设置了目标使用率,
控制器获取每个 Pod 中的容器资源使用情况,并计算资源使用率。
如果设置了 target 值,将直接使用原始数据(不再计算百分比)。
接下来,控制器根据平均的资源使用率或原始值计算出扩缩的比例,进而计算出目标副本数。
需要注意的是,如果 Pod 某些容器不支持资源采集,那么控制器将不会使用该 Pod 的 CPU 使用率。
下面的算法细节 章节将会介绍详细的算法。
如果 Pod 使用自定义指示,控制器机制与资源指标类似,区别在于自定义指标只使用
原始值,而不是使用率。 如果 Pod 使用对象指标和外部指标(每个指标描述一个对象信息)。
这个指标将直接根据目标设定值相比较,并生成一个上面提到的扩缩比例。
在 autoscaling/v2beta2 版本 API 中,这个指标也可以根据 Pod 数量平分后再计算。 通常情况下,控制器将从一系列的聚合 API(metrics.k8s.io、custom.metrics.k8s.io
和 external.metrics.k8s.io)中获取度量值。
metrics.k8s.io API 通常由 Metrics 服务器(需要额外启动)提供。
可以从 metrics-server 获取更多信息。
另外,控制器也可以直接从 Heapster 获取指标。
说明: FEATURE STATE: Kubernetes 1.11 [deprecated]
自 Kubernetes 1.11 起,从 Heapster 获取指标特性已废弃。
关于指标 API 更多信息,请参考度量值指标 API 的支持 。
自动扩缩控制器使用 scale 子资源访问相应可支持扩缩的控制器(如副本控制器、
Deployment 和 ReplicaSet)。
scale 是一个可以动态设定副本数量和检查当前状态的接口。
关于 scale 子资源的更多信息,请参考这里 .
算法细节 从最基本的角度来看,Pod 水平自动扩缩控制器根据当前指标和期望指标来计算扩缩比例。
期望副本数 = ceil[当前副本数 * (当前指标 / 期望指标)]
例如,当前度量值为 200m,目标设定值为 100m,那么由于 200.0/100.0 == 2.0,
副本数量将会翻倍。
如果当前指标为 50m,副本数量将会减半,因为50.0/100.0 == 0.5。
如果计算出的扩缩比例接近 1.0
(根据--horizontal-pod-autoscaler-tolerance 参数全局配置的容忍值,默认为 0.1),
将会放弃本次扩缩。
如果 HorizontalPodAutoscaler 指定的是 targetAverageValue 或 targetAverageUtilization,
那么将会把指定 Pod 度量值的平均值做为 currentMetricValue。
然而,在检查容忍度和决定最终扩缩值前,我们仍然会把那些无法获取指标的 Pod 统计进去。
所有被标记了删除时间戳(Pod 正在关闭过程中)的 Pod 和失败的 Pod 都会被忽略。
如果某个 Pod 缺失度量值,它将会被搁置,只在最终确定扩缩数量时再考虑。
当使用 CPU 指标来扩缩时,任何还未就绪(例如还在初始化)状态的 Pod 或 最近的指标
度量值采集于就绪状态前的 Pod,该 Pod 也会被搁置。
由于受技术限制,Pod 水平扩缩控制器无法准确的知道 Pod 什么时候就绪,
也就无法决定是否暂时搁置该 Pod。
--horizontal-pod-autoscaler-initial-readiness-delay 参数(默认为 30s)用于设置 Pod 准备时间,
在此时间内的 Pod 统统被认为未就绪。
--horizontal-pod-autoscaler-cpu-initialization-period 参数(默认为5分钟)
用于设置 Pod 的初始化时间,
在此时间内的 Pod,CPU 资源度量值将不会被采纳。
在排除掉被搁置的 Pod 后,扩缩比例就会根据 currentMetricValue/desiredMetricValue
计算出来。
如果缺失任何的度量值,我们会更保守地重新计算平均值,
在需要缩小时假设这些 Pod 消耗了目标值的 100%,
在需要放大时假设这些 Pod 消耗了 0% 目标值。
这可以在一定程度上抑制扩缩的幅度。
此外,如果存在任何尚未就绪的 Pod,我们可以在不考虑遗漏指标或尚未就绪的 Pod 的情况下进行扩缩,
我们保守地假设尚未就绪的 Pod 消耗了期望指标的 0%,从而进一步降低了扩缩的幅度。
在扩缩方向(缩小或放大)确定后,我们会把未就绪的 Pod 和缺少指标的 Pod 考虑进来再次计算使用率。
如果新的比率与扩缩方向相反,或者在容忍范围内,则跳过扩缩。
否则,我们使用新的扩缩比例。
注意,平均利用率的原始 值会通过 HorizontalPodAutoscaler 的状态体现(
即使使用了新的使用率,也不考虑未就绪 Pod 和 缺少指标的 Pod)。
如果创建 HorizontalPodAutoscaler 时指定了多个指标,
那么会按照每个指标分别计算扩缩副本数,取最大值进行扩缩。
如果任何一个指标无法顺利地计算出扩缩副本数(比如,通过 API 获取指标时出错),
并且可获取的指标建议缩容,那么本次扩缩会被跳过。
这表示,如果一个或多个指标给出的 desiredReplicas 值大于当前值,HPA 仍然能实现扩容。
最后,在 HPA 控制器执行扩缩操作之前,会记录扩缩建议信息。
控制器会在操作时间窗口中考虑所有的建议信息,并从中选择得分最高的建议。
这个值可通过 kube-controller-manager 服务的启动参数 --horizontal-pod-autoscaler-downscale-stabilization 进行配置,
默认值为 5 分钟。
这个配置可以让系统更为平滑地进行缩容操作,从而消除短时间内指标值快速波动产生的影响。
API 对象 HorizontalPodAutoscaler 是 Kubernetes autoscaling API 组的资源。
在当前稳定版本(autoscaling/v1)中只支持基于 CPU 指标的扩缩。
API 的 beta 版本(autoscaling/v2beta2)引入了基于内存和自定义指标的扩缩。
在 autoscaling/v2beta2 版本中新引入的字段在 autoscaling/v1 版本中以注解
的形式得以保留。
创建 HorizontalPodAutoscaler 对象时,需要确保所给的名称是一个合法的
DNS 子域名 。
有关 API 对象的更多信息,请查阅
HorizontalPodAutoscaler 对象设计文档 。
kubectl 对 Horizontal Pod Autoscaler 的支持 与其他 API 资源类似,kubectl 以标准方式支持 HPA。
我们可以通过 kubectl create 命令创建一个 HPA 对象,
通过 kubectl get hpa 命令来获取所有 HPA 对象,
通过 kubectl describe hpa 命令来查看 HPA 对象的详细信息。
最后,可以使用 kubectl delete hpa 命令删除对象。
此外,还有个简便的命令 kubectl autoscale 来创建 HPA 对象。
例如,命令 kubectl autoscale rs foo --min=2 --max=5 --cpu-percent=80 将会为名
为 foo 的 ReplicationSet 创建一个 HPA 对象,
目标 CPU 使用率为 80%,副本数量配置为 2 到 5 之间。
滚动升级时扩缩 目前在 Kubernetes 中,可以针对 ReplicationController 或 Deployment 执行
滚动更新,它们会为你管理底层副本数。
Pod 水平扩缩只支持后一种:HPA 会被绑定到 Deployment 对象,
HPA 设置副本数量时,Deployment 会设置底层副本数。
通过直接操控副本控制器执行滚动升级时,HPA 不能工作,
也就是说你不能将 HPA 绑定到某个 RC 再执行滚动升级。
HPA 不能工作的原因是它无法绑定到滚动更新时所新创建的副本控制器。
冷却/延迟支持 当使用 Horizontal Pod Autoscaler 管理一组副本扩缩时,
有可能因为指标动态的变化造成副本数量频繁的变化,有时这被称为
抖动(Thrashing) 。
从 v1.6 版本起,集群操作员可以调节某些 kube-controller-manager 的全局参数来
缓解这个问题。
从 v1.12 开始,算法调整后,扩容操作时的延迟就不必设置了。
--horizontal-pod-autoscaler-downscale-stabilization:
kube-controller-manager 的这个参数表示缩容冷却时间。
即自从上次缩容执行结束后,多久可以再次执行缩容,默认时间是 5 分钟(5m0s)。说明: 当调整这些参数时,集群操作员需要明白其可能的影响。
如果延迟(冷却)时间设置的太长,Horizontal Pod Autoscaler 可能会不能很好的改变负载。
如果延迟(冷却)时间设置的太短,那么副本数量有可能跟以前一样出现抖动。
对资源指标的支持 HPA 的任何目标资源都可以基于其中的 Pods 的资源用量来实现扩缩。
在定义 Pod 规约时,类似 cpu 和 memory 这类资源请求必须被设定。
这些设定值被用来确定资源利用量并被 HPA 控制器用来对目标资源完成扩缩操作。
要使用基于资源利用率的扩缩,可以像下面这样指定一个指标源:
type : Resource
resource :
name : cpu
target :
type : Utilization
averageUtilization : 60
基于这一指标设定,HPA 控制器会维持扩缩目标中的 Pods 的平均资源利用率在 60%。
利用率是 Pod 的当前资源用量与其请求值之间的比值。关于如何计算利用率以及如何计算平均值
的细节可参考算法 小节。
说明: 由于所有的容器的资源用量都会被累加起来,Pod 的总体资源用量值可能不会精确体现
各个容器的资源用量。这一现象也会导致一些问题,例如某个容器运行时的资源用量非常
高,但因为 Pod 层面的资源用量总值让人在可接受的约束范围内,HPA 不会执行扩大
目标对象规模的操作。
容器资源指标 FEATURE STATE: Kubernetes v1.20 [alpha]
HorizontalPodAutoscaler 也支持容器指标源,这时 HPA 可以跟踪记录一组 Pods 中各个容器的
资源用量,进而触发扩缩目标对象的操作。
容器资源指标的支持使得你可以为特定 Pod 中最重要的容器配置规模缩放阈值。
例如,如果你有一个 Web 应用和一个执行日志操作的边车容器,你可以基于 Web 应用的
资源用量来执行扩缩,忽略边车容器的存在及其资源用量。
如果你更改缩放目标对象,令其使用新的、包含一组不同的容器的 Pod 规约,你就需要
修改 HPA 的规约才能基于新添加的容器来执行规模扩缩操作。
如果指标源中指定的容器不存在或者仅存在于部分 Pods 中,那么这些 Pods 会被忽略,
HPA 会重新计算资源用量值。参阅算法 小节进一步了解计算细节。
要使用容器资源用量来完成自动扩缩,可以像下面这样定义指标源:
type : ContainerResource
containerResource :
name : cpu
container : application
target :
type : Utilization
averageUtilization : 60
在上面的例子中,HPA 控制器会对目标对象执行扩缩操作以确保所有 Pods 中
application 容器的平均 CPU 用量为 60%。
说明: 如果你要更改 HorizontalPodAutoscaler 所跟踪记录的容器的名称,你可以按一定顺序
来执行这一更改,确保在应用更改的过程中用来判定扩缩行为的容器可用。
在更新定义容器的资源(如 Deployment)之前,你需要更新相关的 HPA,使之能够同时
跟踪记录新的和老的容器名称。这样,HPA 就能够在整个更新过程中继续计算并提供扩缩操作建议。
一旦你已经将容器名称变更这一操作应用到整个负载对象至上,就可以从 HPA
的规约中去掉老的容器名称,完成清理操作。
多指标支持 Kubernetes 1.6 开始支持基于多个度量值进行扩缩。
你可以使用 autoscaling/v2beta2 API 来为 Horizontal Pod Autoscaler 指定多个指标。
Horizontal Pod Autoscaler 会根据每个指标计算,并生成一个扩缩建议。
幅度最大的扩缩建议会被采纳。
自定义指标支持 说明: 在 Kubernetes 1.2 增加了支持基于使用特殊注解表达的、特定于具体应用的扩缩能力,
此能力处于 Alpha 阶段。
从 Kubernetes 1.6 起,由于新的 autoscaling API 的引入,这些 annotation 就被废弃了。
虽然收集自定义指标的旧方法仍然可用,Horizontal Pod Autoscaler 调度器将不会再使用这些度量值。
同时,Horizontal Pod Autoscaler 也不再使用之前用于指定用户自定义指标的注解。
自 Kubernetes 1.6 起,Horizontal Pod Autoscaler 支持使用自定义指标。
你可以使用 autoscaling/v2beta2 API 为 Horizontal Pod Autoscaler 指定用户自定义指标。
Kubernetes 会通过用户自定义指标 API 来获取相应的指标。
关于指标 API 的要求,请参阅对 Metrics API 的支持 。
对 Metrics API 的支持 默认情况下,HorizontalPodAutoscaler 控制器会从一系列的 API 中检索度量值。
集群管理员需要确保下述条件,以保证 HPA 控制器能够访问这些 API:
关于指标来源以及其区别的更多信息,请参阅相关的设计文档,
the HPA V2 、
custom.metrics.k8s.io 和
external.metrics.k8s.io 。
关于如何使用它们的示例,请参考
使用自定义指标的教程
和使用外部指标的教程 。
支持可配置的扩缩 从 v1.18
开始,v2beta2 API 允许通过 HPA 的 behavior 字段配置扩缩行为。
在 behavior 字段中的 scaleUp 和 scaleDown 分别指定扩容和缩容行为。
可以两个方向指定一个稳定窗口,以防止扩缩目标中副本数量的波动。
类似地,指定扩缩策略可以控制扩缩时副本数的变化率。
扩缩策略 在 spec 字段的 behavior 部分可以指定一个或多个扩缩策略。
当指定多个策略时,默认选择允许更改最多的策略。
下面的例子展示了缩容时的行为:
behavior :
scaleDown :
policies :
- type : Pods
value : 4
periodSeconds : 60
- type : Percent
value : 10
periodSeconds : 60
当 Pod 数量超过 40 个时,第二个策略将用于缩容。
例如,如果有 80 个副本,并且目标必须缩小到 10 个副本,那么在第一步中将减少 8 个副本。
在下一轮迭代中,当副本的数量为 72 时,10% 的 Pod 数为 7.2,但是这个数字向上取整为 8。
在 autoscaler 控制器的每个循环中,将根据当前副本的数量重新计算要更改的 Pod 数量。
当副本数量低于 40 时,应用第一个策略 (Pods) ,一次减少 4 个副本。
periodSeconds 表示策略的时间长度必须保证有效。
第一个策略允许在一分钟内最多缩小 4 个副本。
第二个策略最多允许在一分钟内缩小当前副本的 10%。
可以指定扩缩方向的 selectPolicy 字段来更改策略选择。
通过设置 Min 的值,它将选择副本数变化最小的策略。
将该值设置为 Disabled 将完全禁用该方向的缩放。
稳定窗口 当用于扩缩的指标持续抖动时,使用稳定窗口来限制副本数上下振动。
自动扩缩算法使用稳定窗口来考虑过去计算的期望状态,以防止扩缩。
在下面的例子中,稳定化窗口被指定为 scaleDown。
scaleDown :
stabilizationWindowSeconds : 300
当指标显示目标应该缩容时,自动扩缩算法查看之前计算的期望状态,并使用指定时间间隔内的最大值。
在上面的例子中,过去 5 分钟的所有期望状态都会被考虑。
默认行为 要使用自定义扩缩,不必指定所有字段。
只有需要自定义的字段才需要指定。
这些自定义值与默认值合并。
默认值与 HPA 算法中的现有行为匹配。
behavior :
scaleDown :
stabilizationWindowSeconds : 300
policies :
- type : Percent
value : 100
periodSeconds : 15
scaleUp :
stabilizationWindowSeconds : 0
policies :
- type : Percent
value : 100
periodSeconds : 15
- type : Pods
value : 4
periodSeconds : 15
selectPolicy : Max
用于缩小稳定窗口的时间为 300 秒(或是 --horizontal-pod-autoscaler-downscale-stabilization 参数设定值)。
只有一种缩容的策略,允许 100% 删除当前运行的副本,这意味着扩缩目标可以缩小到允许的最小副本数。
对于扩容,没有稳定窗口。当指标显示目标应该扩容时,目标会立即扩容。
这里有两种策略,每 15 秒添加 4 个 Pod 或 100% 当前运行的副本数,直到 HPA 达到稳定状态。
示例:更改缩容稳定窗口 将下面的 behavior 配置添加到 HPA 中,可提供一个 1 分钟的自定义缩容稳定窗口:
behavior :
scaleDown :
stabilizationWindowSeconds : 60
示例:限制缩容速率 将下面的 behavior 配置添加到 HPA 中,可限制 Pod 被 HPA 删除速率为每分钟 10%:
behavior :
scaleDown :
policies :
- type : Percent
value : 10
periodSeconds : 60
为了确保每分钟删除的 Pod 数不超过 5 个,可以添加第二个缩容策略,大小固定为 5,并将 selectPolicy 设置为最小值。
将 selectPolicy 设置为 Min 意味着 autoscaler 会选择影响 Pod 数量最小的策略:
behavior :
scaleDown :
policies :
- type : Percent
value : 10
periodSeconds : 60
- type : Pods
value : 5
periodSeconds : 60
selectPolicy : Min
示例:禁用缩容 selectPolicy 的值 Disabled 会关闭对给定方向的缩容。
因此使用以下策略,将会阻止缩容:
behavior :
scaleDown :
selectPolicy : Disabled
隐式维护状态禁用 你可以在不必更改 HPA 配置的情况下隐式地为某个目标禁用 HPA。
如果此目标的期望副本个数被设置为 0,而 HPA 的最小副本个数大于 0,
则 HPA 会停止调整目标(并将其自身的 ScalingActive 状况设置为 false),
直到你通过手动调整目标的期望副本个数或 HPA 的最小副本个数来重新激活。
接下来 4.7.6 - Horizontal Pod Autoscaler 演练 Horizontal Pod Autoscaler 可以根据 CPU 利用率自动扩缩 ReplicationController、
Deployment、ReplicaSet 或 StatefulSet 中的 Pod 数量
(也可以基于其他应用程序提供的度量指标,目前这一功能处于 beta 版本)。
本文将引领你了解如何为 php-apache 服务器配置和使用 Horizontal Pod Autoscaler。
与 Horizontal Pod Autoscaler 相关的更多信息请参阅
Horizontal Pod Autoscaler 用户指南 。
准备开始 本文示例需要一个运行中的 Kubernetes 集群以及 kubectl,版本为 1.2 或更高。
Metrics 服务器
需要被部署到集群中,以便通过 Metrics API
提供度量数据。
Horizontal Pod Autoscaler 根据此 API 来获取度量数据。
要了解如何部署 metrics-server,请参考
metrics-server 文档 。
如果需要为 Horizontal Pod Autoscaler 指定多种资源度量指标,你的 Kubernetes
集群以及 kubectl 至少需要达到 1.6 版本。
此外,如果要使用自定义度量指标,你的 Kubernetes 集群还必须能够与提供这些自定义指标
的 API 服务器通信。
最后,如果要使用与 Kubernetes 对象无关的度量指标,则 Kubernetes 集群版本至少需要
达到 1.10 版本,同样,需要保证集群能够与提供这些外部指标的 API 服务器通信。
更多详细信息,请参阅
Horizontal Pod Autoscaler 用户指南 。
运行 php-apache 服务器并暴露服务 为了演示 Horizontal Pod Autoscaler,我们将使用一个基于 php-apache 镜像的
定制 Docker 镜像。Dockerfile 内容如下:
FROM php:5-apache
COPY index.php /var/www/html/index.php
RUN chmod a+rx index.php
该文件定义了一个 index.php 页面来执行一些 CPU 密集型计算:
<?php
$x = 0.0001;
for ($i = 0; $i <= 1000000; $i++) {
$x += sqrt($x);
}
echo "OK!";
?>
首先,我们使用下面的配置启动一个 Deployment 来运行这个镜像并暴露一个服务:
apiVersion : apps/v1
kind : Deployment
metadata :
name : php-apache
spec :
selector :
matchLabels :
run : php-apache
replicas : 1
template :
metadata :
labels :
run : php-apache
spec :
containers :
- name : php-apache
image : k8s.gcr.io/hpa-example
ports :
- containerPort : 80
resources :
limits :
cpu : 500m
requests :
cpu : 200m
---
apiVersion : v1
kind : Service
metadata :
name : php-apache
labels :
run : php-apache
spec :
ports :
- port : 80
selector :
run : php-apache
运行下面的命令:
kubectl apply -f https://k8s.io/examples/application/php-apache.yaml
deployment.apps/php-apache created
service/php-apache created
创建 Horizontal Pod Autoscaler 现在,php-apache 服务器已经运行,我们将通过
kubectl autoscale
命令创建 Horizontal Pod Autoscaler。
以下命令将创建一个 Horizontal Pod Autoscaler 用于控制我们上一步骤中创建的
Deployment,使 Pod 的副本数量维持在 1 到 10 之间。
大致来说,HPA 将(通过 Deployment)增加或者减少 Pod 副本的数量以保持所有 Pod
的平均 CPU 利用率在 50% 左右(由于每个 Pod 请求 200 毫核的 CPU,这意味着平均
CPU 用量为 100 毫核)。
算法的详情请参阅相关文档 。
kubectl autoscale deployment php-apache --cpu-percent= 50 --min= 1 --max= 10
horizontalpodautoscaler.autoscaling/php-apache autoscaled
我们可以通过以下命令查看 Autoscaler 的状态:
NAME REFERENCE TARGET MINPODS MAXPODS REPLICAS AGE
php-apache Deployment/php-apache/scale 0% / 50% 1 10 1 18s
请注意当前的 CPU 利用率是 0%,这是由于我们尚未发送任何请求到服务器
(CURRENT 列显示了相应 Deployment 所控制的所有 Pod 的平均 CPU 利用率)。
增加负载 现在,我们将看到 Autoscaler 如何对增加负载作出反应。
我们将启动一个容器,并通过一个循环向 php-apache 服务器发送无限的查询请求
(请在另一个终端中运行以下命令):
kubectl run -i --tty load-generator --rm --image= busybox --restart= Never -- /bin/sh -c "while sleep 0.01; do wget -q -O- http://php-apache; done"
一分钟时间左右之后,通过以下命令,我们可以看到 CPU 负载升高了:
NAME REFERENCE TARGET MINPODS MAXPODS REPLICAS AGE
php-apache Deployment/php-apache/scale 305% / 50% 1 10 1 3m
这时,由于请求增多,CPU 利用率已经升至请求值的 305%。
可以看到,Deployment 的副本数量已经增长到了 7:
kubectl get deployment php-apache
NAME READY UP-TO-DATE AVAILABLE AGE
php-apache 7/7 7 7 19m
说明: 有时最终副本的数量可能需要几分钟才能稳定下来。由于环境的差异,
不同环境中最终的副本数量可能与本示例中的数量不同。
停止负载 我们将通过停止负载来结束我们的示例。
在我们创建 busybox 容器的终端中,输入<Ctrl> + C 来终止负载的产生。
然后我们可以再次检查负载状态(等待几分钟时间):
NAME REFERENCE TARGET MINPODS MAXPODS REPLICAS AGE
php-apache Deployment/php-apache/scale 0% / 50% 1 10 1 11m
kubectl get deployment php-apache
NAME READY UP-TO-DATE AVAILABLE AGE
php-apache 1/1 1 1 27m
这时,CPU 利用率已经降到 0,所以 HPA 将自动缩减副本数量至 1。
说明: 自动扩缩完成副本数量的改变可能需要几分钟的时间。
基于多项度量指标和自定义度量指标自动扩缩 利用 autoscaling/v2beta2 API 版本,你可以在自动扩缩 php-apache 这个
Deployment 时使用其他度量指标。
首先,将 HorizontalPodAutoscaler 的 YAML 文件改为 autoscaling/v2beta2 格式:
kubectl get hpa.v2beta2.autoscaling -o yaml > /tmp/hpa-v2.yaml
在编辑器中打开 /tmp/hpa-v2.yaml:
apiVersion : autoscaling/v2beta2
kind : HorizontalPodAutoscaler
metadata :
name : php-apache
spec :
scaleTargetRef :
apiVersion : apps/v1
kind : Deployment
name : php-apache
minReplicas : 1
maxReplicas : 10
metrics :
- type : Resource
resource :
name : cpu
target :
type : Utilization
averageUtilization : 50
status :
observedGeneration : 1
lastScaleTime : <some-time>
currentReplicas : 1
desiredReplicas : 1
currentMetrics :
- type : Resource
resource :
name : cpu
current :
averageUtilization : 0
averageValue : 0
需要注意的是,targetCPUUtilizationPercentage 字段已经被名为 metrics 的数组所取代。
CPU 利用率这个度量指标是一个 resource metric (资源度量指标),因为它表示容器上指定资源的百分比。
除 CPU 外,你还可以指定其他资源度量指标。默认情况下,目前唯一支持的其他资源度量指标为内存。
只要 metrics.k8s.io API 存在,这些资源度量指标就是可用的,并且他们不会在不同的 Kubernetes 集群中改变名称。
你还可以指定资源度量指标使用绝对数值,而不是百分比,你需要将 target.type 从
Utilization 替换成 AverageValue,同时设置 target.averageValue
而非 target.averageUtilization 的值。
还有两种其他类型的度量指标,他们被认为是 custom metrics (自定义度量指标):
即 Pod 度量指标和 Object 度量指标。
这些度量指标可能具有特定于集群的名称,并且需要更高级的集群监控设置。
第一种可选的度量指标类型是 Pod 度量指标。这些指标从某一方面描述了 Pod,
在不同 Pod 之间进行平均,并通过与一个目标值比对来确定副本的数量。
它们的工作方式与资源度量指标非常相像,只是它们仅支持 target 类型为 AverageValue。
pod 度量指标通过如下代码块定义:
type : Pods
pods :
metric :
name : packets-per-second
target :
type : AverageValue
averageValue : 1k
第二种可选的度量指标类型是对象(Object)度量指标。这些度量指标用于描述
在相同名字空间中的别的对象,而非 Pods。
请注意这些度量指标不一定来自某对象,它们仅用于描述这些对象。
对象度量指标支持的 target 类型包括 Value 和 AverageValue。
如果是 Value 类型,target 值将直接与 API 返回的度量指标比较,
而对于 AverageValue 类型,API 返回的度量值将按照 Pod 数量拆分,
然后再与 target 值比较。
下面的 YAML 文件展示了一个表示 requests-per-second 的度量指标。
type : Object
object :
metric :
name : requests-per-second
describedObject :
apiVersion : networking.k8s.io/v1
kind : Ingress
name : main-route
target :
type : Value
value : 2k
如果你指定了多个上述类型的度量指标,HorizontalPodAutoscaler 将会依次考量各个指标。
HorizontalPodAutoscaler 将会计算每一个指标所提议的副本数量,然后最终选择一个最高值。
比如,如果你的监控系统能够提供网络流量数据,你可以通过 kubectl edit 命令
将上述 Horizontal Pod Autoscaler 的定义更改为:
apiVersion : autoscaling/v2beta1
kind : HorizontalPodAutoscaler
metadata :
name : php-apache
spec :
scaleTargetRef :
apiVersion : apps/v1
kind : Deployment
name : php-apache
minReplicas : 1
maxReplicas : 10
metrics :
- type : Resource
resource :
name : cpu
target :
type : AverageUtilization
averageUtilization : 50
- type : Pods
pods :
metric :
name : packets-per-second
target :
type : AverageValue
averageValue : 1k
- type : Object
object :
metric :
name : requests-per-second
describedObject :
apiVersion : networking.k8s.io/v1beta1
kind : Ingress
name : main-route
target :
kind : Value
value : 10k
status :
observedGeneration : 1
lastScaleTime : <some-time>
currentReplicas : 1
desiredReplicas : 1
currentMetrics :
- type : Resource
resource :
name : cpu
current :
averageUtilization : 0
averageValue : 0
- type : Object
object :
metric :
name : requests-per-second
describedObject :
apiVersion : networking.k8s.io/v1beta1
kind : Ingress
name : main-route
current :
value : 10k
这样,你的 HorizontalPodAutoscaler 将会尝试确保每个 Pod 的 CPU 利用率在 50% 以内,
每秒能够服务 1000 个数据包请求,
并确保所有在 Ingress 后的 Pod 每秒能够服务的请求总数达到 10000 个。
基于更特别的度量值来扩缩 许多度量流水线允许你通过名称或附加的 标签 来描述度量指标。
对于所有非资源类型度量指标(Pod、Object 和后面将介绍的 External),
可以额外指定一个标签选择算符。例如,如果你希望收集包含 verb 标签的
http_requests 度量指标,可以按如下所示设置度量指标块,使得扩缩操作仅针对
GET 请求执行:
type : Object
object :
metric :
name : `http_requests`
selector : `verb=GET`
这个选择算符使用与 Kubernetes 标签选择算符相同的语法。
如果名称和标签选择算符匹配到多个系列,监测管道会决定如何将多个系列合并成单个值。
选择算符是可以累加的,它不会选择目标以外的对象(类型为 Pods 的目标 Pods 或者
类型为 Object 的目标对象)。
基于与 Kubernetes 对象无关的度量指标执行扩缩 运行在 Kubernetes 上的应用程序可能需要基于与 Kubernetes 集群中的任何对象
没有明显关系的度量指标进行自动扩缩,
例如那些描述与任何 Kubernetes 名字空间中的服务都无直接关联的度量指标。
在 Kubernetes 1.10 及之后版本中,你可以使用外部度量指标(external metrics)。
使用外部度量指标时,需要了解你所使用的监控系统,相关的设置与使用自定义指标时类似。
外部度量指标使得你可以使用你的监控系统的任何指标来自动扩缩你的集群。
你只需要在 metric 块中提供 name 和 selector,同时将类型由 Object 改为 External。
如果 metricSelector 匹配到多个度量指标,HorizontalPodAutoscaler 将会把它们加和。
外部度量指标同时支持 Value 和 AverageValue 类型,这与 Object 类型的度量指标相同。
例如,如果你的应用程序处理来自主机上消息队列的任务,
为了让每 30 个任务有 1 个工作者实例,你可以将下面的内容添加到
HorizontalPodAutoscaler 的配置中。
- type : External
external :
metric :
name : queue_messages_ready
selector : "queue=worker_tasks"
target :
type : AverageValue
averageValue : 30
如果可能,还是推荐定制度量指标而不是外部度量指标,因为这便于让系统管理员加固定制度量指标 API。
而外部度量指标 API 可以允许访问所有的度量指标。
当暴露这些服务时,系统管理员需要仔细考虑这个问题。
附录:Horizontal Pod Autoscaler 状态条件 使用 autoscaling/v2beta2 格式的 HorizontalPodAutoscaler 时,你将可以看到
Kubernetes 为 HorizongtalPodAutoscaler 设置的状态条件(Status Conditions)。
这些状态条件可以显示当前 HorizontalPodAutoscaler 是否能够执行扩缩以及是否受到一定的限制。
status.conditions 字段展示了这些状态条件。
可以通过 kubectl describe hpa 命令查看当前影响 HorizontalPodAutoscaler
的各种状态条件信息:
kubectl describe hpa cm-test
Name: cm-test
Namespace: prom
Labels: <none>
Annotations: <none>
CreationTimestamp: Fri, 16 Jun 2017 18:09:22 +0000
Reference: ReplicationController/cm-test
Metrics: ( current / target )
"http_requests" on pods: 66m / 500m
Min replicas: 1
Max replicas: 4
ReplicationController pods: 1 current / 1 desired
Conditions:
Type Status Reason Message
---- ------ ------ -------
AbleToScale True ReadyForNewScale the last scale time was sufficiently old as to warrant a new scale
ScalingActive True ValidMetricFound the HPA was able to successfully calculate a replica count from pods metric http_requests
ScalingLimited False DesiredWithinRange the desired replica count is within the acceptable range
Events:
对于上面展示的这个 HorizontalPodAutoscaler,我们可以看出有若干状态条件处于健康状态。
首先,AbleToScale 表明 HPA 是否可以获取和更新扩缩信息,以及是否存在阻止扩缩的各种回退条件。
其次,ScalingActive 表明 HPA 是否被启用(即目标的副本数量不为零) 以及是否能够完成扩缩计算。
当这一状态为 False 时,通常表明获取度量指标存在问题。
最后一个条件 ScalingLimitted 表明所需扩缩的值被 HorizontalPodAutoscaler
所定义的最大或者最小值所限制(即已经达到最大或者最小扩缩值)。
这通常表明你可能需要调整 HorizontalPodAutoscaler 所定义的最大或者最小副本数量的限制了。
附录:量纲 HorizontalPodAutoscaler 和 度量指标 API 中的所有的度量指标使用 Kubernetes 中称为
量纲(Quantity)
的特殊整数表示。
例如,数量 10500m 用十进制表示为 10.5。
如果可能的话,度量指标 API 将返回没有后缀的整数,否则返回以千分单位的数量。
这意味着你可能会看到你的度量指标在 1 和 1500m (也就是在十进制记数法中的 1 和 1.5)之间波动。
附录:其他可能的情况 以声明式方式创建 Autoscaler 除了使用 kubectl autoscale 命令,也可以文件创建 HorizontalPodAutoscaler:
apiVersion : autoscaling/v1
kind : HorizontalPodAutoscaler
metadata :
name : php-apache
spec :
scaleTargetRef :
apiVersion : apps/v1
kind : Deployment
name : php-apache
minReplicas : 1
maxReplicas : 10
targetCPUUtilizationPercentage : 50
使用如下命令创建 autoscaler:
kubectl create -f https://k8s.io/examples/application/hpa/php-apache.yaml
horizontalpodautoscaler.autoscaling/php-apache created
4.7.7 - 为应用程序设置干扰预算(Disruption Budget) FEATURE STATE: Kubernetes v1.5 [beta]
本文展示如何限制应用程序的并发干扰数量,在允许集群管理员管理集群节点的同时保证高可用。
准备开始 你是 Kubernetes 集群中某应用的所有者,该应用有高可用要求。 你应了解如何部署无状态应用
和/或有状态应用 。 你应当已经阅读过关于 Pod 干扰 的文档。 用户应当与集群所有者或服务提供者确认其遵从 Pod 干扰预算(Pod Disruption Budgets)的规则。 用 PodDisruptionBudget 来保护应用 确定想要使用 PodDisruptionBudget (PDB) 来保护的应用。 考虑应用对干扰的反应。 以 YAML 文件形式定义 PDB 。 通过 YAML 文件创建 PDB 对象。 确定要保护的应用 用户想要保护通过内置的 Kubernetes 控制器指定的应用,这是最常见的使用场景:
Deployment ReplicationController ReplicaSet StatefulSet 在这种情况下,在控制器的 .spec.selector 字段中做记录,并在 PDB 的
.spec.selector 字段中加入同样的选择算符。
从 1.15 版本开始,PDB 支持启用
scale 子资源
的自定义控制器。
用户也可以用 PDB 来保护不受上述控制器控制的 Pod,或任意的 Pod 集合,但是正如
任意控制器和选择算符 中描述的,这里存在一些限制。
考虑应用对干扰的反应 确定在自发干扰时,多少实例可以在短时间内同时关闭。
无状态的前端:关注:不能降低服务能力 10% 以上。解决方案:例如,使用 PDB,指定其 minAvailable 值为 90%。 单实例有状态应用:关注:不要在不通知的情况下终止该应用。可能的解决方案 1:不使用 PDB,并忍受偶尔的停机。 可能的解决方案 2:设置 maxUnavailable=0 的 PDB。
意为(Kubernetes 范畴之外的)集群操作人员需要在终止应用前与用户协商,
协商后准备停机,然后删除 PDB 表示准备接受干扰,后续再重新创建。 多实例有状态应用,如 Consul、ZooKeeper 或 etcd:关注:不要将实例数量减少至低于仲裁规模,否则将出现写入失败。可能的解决方案 1:设置 maxUnavailable 值为 1 (适用于不同规模的应用)。 可能的解决方案 2:设置 minAvailable 值为仲裁规模(例如规模为 5 时设置为 3)。
(允许同时出现更多的干扰)。 可重新启动的批处理任务:关注:自发干扰的情况下,需要确保任务完成。可能的解决方案:不创建 PDB。 任务控制器会创建一个替换 Pod。 指定百分比时的舍入逻辑 minAvailable 或 maxUnavailable 的值可以表示为整数或百分比。
指定整数值时,它表示 Pod 个数。例如,如果将 minAvailable 设置为 10,
那么即使在干扰期间,也必须始终有 10 个Pod可用。 通过将值设置为百分比的字符串表示形式(例如 “50%”)来指定百分比时,它表示占总 Pod 数的百分比。
例如,如果将 "minUnavailable" 设置为 “50%”,则干扰期间只允许 50% 的 Pod 不可用。 如果将值指定为百分比,则可能无法映射到确切数量的 Pod。例如,如果你有 7 个 Pod,
并且你将 minAvailable 设置为 "50%",具体是 3 个 Pod 或 4 个 Pod 必须可用
并非显而易见。
Kubernetes 采用向上取整到最接近的整数的办法,因此在这种情况下,必须有 4 个 Pod。
你可以检查控制此行为的
代码 。
指定 PodDisruptionBudget 一个 PodDisruptionBudget 有 3 个字段:
标签选择算符 .spec.selector 用于指定其所作用的 Pod 集合,该字段为必需字段。 .spec.minAvailable 表示驱逐后仍须保证可用的 Pod 数量。即使因此影响到 Pod 驱逐
(即该条件在和 Pod 驱逐发生冲突时优先保证)。
minAvailable 值可以是绝对值,也可以是百分比。.spec.maxUnavailable (Kubernetes 1.7 及更高的版本中可用)表示驱逐后允许不可用的
Pod 的最大数量。其值可以是绝对值或是百分比。说明: 对于1.8及更早的版本:当你用 kubectl 命令行工具创建 PodDisruptionBudget 对象时,
如果既未指定 minAvailable 也未指定 maxUnavailable,
则 minAvailable 字段有一个默认值 1。
用户在同一个 PodDisruptionBudget 中只能够指定 maxUnavailable 和 minAvailable 中的一个。
maxUnavailable 只能够用于控制存在相应控制器的 Pod 的驱逐(即不受控制器控制的 Pod 不在
maxUnavailable 控制范围内)。在下面的示例中,
“所需副本” 指的是相应控制器的 scale,控制器对 PodDisruptionBudget 所选择的 Pod 进行管理。
示例 1:设置 minAvailable 值为 5 的情况下,驱逐时需保证 PodDisruptionBudget 的 selector
选中的 Pod 中 5 个或 5 个以上处于健康状态。
示例 2:设置 minAvailable 值为 30% 的情况下,驱逐时需保证 Pod 所需副本的至少 30% 处于健康状态。
示例 3:设置 maxUnavailable 值为 5 的情况下,驱逐时需保证所需副本中最多 5 个处于不可用状态。
示例 4:设置 maxUnavailable 值为 30% 的情况下,驱逐时需保证所需副本中最多 30% 处于不可用状态。
在典型用法中,干扰预算会被用于一个控制器管理的一组 Pod 中 —— 例如:一个 ReplicaSet 或 StatefulSet
中的 Pod。
说明: 干扰预算并不能真正保证指定数量/百分比的 Pod 一直处于运行状态。例如: 当 Pod 集合的
规模处于预算指定的最小值时,承载集合中某个 Pod 的节点发生了故障,这样就导致集合中可用 Pod 的
数量低于预算指定值。预算只能够针对自发的驱逐提供保护,而不能针对所有 Pod 不可用的诱因。
设置 maxUnavailable 值为 0%(或 0)或设置 minAvailable 值为 100%(或等于副本数)
可能会阻塞节点,导致资源耗尽。按照 PodDisruptionBudget 的语义,这是允许的。
用户可以在下面看到 pod 干扰预算定义的示例,它们与带有 app: zookeeper 标签的 pod 相匹配:
使用 minAvailable 的PDB 示例:
apiVersion : policy/v1beta1
kind : PodDisruptionBudget
metadata :
name : zk-pdb
spec :
minAvailable : 2
selector :
matchLabels :
app : zookeeper
使用 maxUnavailable 的 PDB 示例(Kubernetes 1.7 或更高的版本):
apiVersion : policy/v1beta1
kind : PodDisruptionBudget
metadata :
name : zk-pdb
spec :
maxUnavailable : 1
selector :
matchLabels :
app : zookeeper
例如,如果上述 zk-pdb 选择的是一个规格为 3 的 StatefulSet 对应的 Pod,
那么上面两种规范的含义完全相同。
推荐使用 maxUnavailable ,因为它自动响应控制器副本数量的变化。
创建 PDB 对象 你可以通过类似 kubectl apply -f mypdb.yaml 的命令来创建 PDB。
PDB 对象无法更新,必须删除后重新创建。
检查 PDB 的状态 使用 kubectl 来确认 PDB 被创建。
假设用户的名字空间下没有匹配 app: zookeeper 的 Pod,用户会看到类似下面的信息:
kubectl get poddisruptionbudgets
NAME MIN AVAILABLE MAX UNAVAILABLE ALLOWED DISRUPTIONS AGE
zk-pdb 2 N/A 0 7s
假设有匹配的 Pod (比如说 3 个), 那么用户会看到类似下面的信息:
kubectl get poddisruptionbudgets
NAME MIN AVAILABLE MAX UNAVAILABLE ALLOWED DISRUPTIONS AGE
zk-pdb 2 N/A 1 7s
ALLOWED-DISRUPTIONS 值非 0 意味着干扰控制器已经感知到相应的 Pod,对匹配的 Pod 进行统计,
并更新了 PDB 的状态。
用户可以通过以下命令获取更多 PDB 状态相关信息:
kubectl get poddisruptionbudgets zk-pdb -o yaml
apiVersion : policy/v1beta1
kind : PodDisruptionBudget
metadata :
anntation : {}
creationTimestamp : "2020-03-04T04:22:56Z"
generation : 1
name : zk-pdb
…
status :
currentHealthy : 3
desiredHealthy : 2
disruptionsAllowed : 1
expectedPods : 3
observedGeneration : 1
任意控制器和选择算符 如果你只使用与内置的应用控制器(Deployment、ReplicationController、ReplicaSet 和 StatefulSet)
对应的 PDB,也就是 PDB 的选择算符与 控制器的选择算符相匹配,那么可以跳过这一节。
你可以使用这样的 PDB:它对应的 Pod 可能由其他类型的控制器控制,可能由 "operator" 控制,
也可能为“裸的(不受控制器控制)” Pod,但该类 PDB 存在以下限制:
只能够使用 .spec.minAvailable ,而不能够使用 .spec.maxUnavailable。 只能够使用整数作为 .spec.minAvailable 的值,而不能使用百分比。 你可以令选择算符选择一个内置控制器所控制 Pod 的子集或父集。
然而,当名字空间下存在多个 PDB 时,用户必须小心,保证 PDB 的选择算符之间不重叠。
4.7.8 - 从 Pod 中访问 Kubernetes API 本指南演示了如何从 Pod 中访问 Kubernetes API。
准备开始 你必须拥有一个 Kubernetes 的集群,同时你的 Kubernetes 集群必须带有 kubectl 命令行工具。
如果你还没有集群,你可以通过 Minikube 构建一
个你自己的集群,或者你可以使用下面任意一个 Kubernetes 工具构建:
从 Pod 中访问 API 从 Pod 内部访问 API 时,定位 API 服务器和向服务器认证身份的操作
与外部客户端场景不同。
从 Pod 使用 Kubernetes API 的最简单的方法就是使用官方的
客户端库 。
这些库可以自动发现 API 服务器并进行身份验证。
使用官方客户端库 从一个 Pod 内部连接到 Kubernetes API 的推荐方式为:
在以上场景中,客户端库都使用 Pod 的服务账号凭据来与 API 服务器安全地通信。
直接访问 REST API 在运行在 Pod 中时,可以通过 default 命名空间中的名为 kubernetes 的服务访问
Kubernetes API 服务器。也就是说,Pod 可以使用 kubernetes.default.svc 主机名
来查询 API 服务器。官方客户端库自动完成这个工作。
向 API 服务器进行身份认证的推荐做法是使用
服务账号 凭据。
默认情况下,每个 Pod 与一个服务账号关联,该服务账户的凭证(令牌)放置在此 Pod 中
每个容器的文件系统树中的 /var/run/secrets/kubernetes.io/serviceaccount/token 处。
如果证书包可用,则凭证包被放入每个容器的文件系统树中的
/var/run/secrets/kubernetes.io/serviceaccount/ca.crt 处,
且将被用于验证 API 服务器的服务证书。
最后,用于命名空间域 API 操作的默认命名空间放置在每个容器中的
/var/run/secrets/kubernetes.io/serviceaccount/namespace 文件中。
使用 kubectl proxy 如果你希望不使用官方客户端库就完成 API 查询,可以将 kubectl proxy 作为
command
在 Pod 中启动一个边车(Sidecar)容器。这样,kubectl proxy 自动完成对 API
的身份认证,并将其暴露到 Pod 的 localhost 接口,从而 Pod 中的其他容器可以
直接使用 API。
不使用代理 通过将认证令牌直接发送到 API 服务器,也可以避免运行 kubectl proxy 命令。
内部的证书机制能够为链接提供保护。
# 指向内部 API 服务器的主机名
APISERVER = https://kubernetes.default.svc
# 服务账号令牌的路径
SERVICEACCOUNT = /var/run/secrets/kubernetes.io/serviceaccount
# 读取 Pod 的名字空间
NAMESPACE = $( cat ${ SERVICEACCOUNT } /namespace)
# 读取服务账号的持有者令牌
TOKEN = $( cat ${ SERVICEACCOUNT } /token)
# 引用内部证书机构(CA)
CACERT = ${ SERVICEACCOUNT } /ca.crt
# 使用令牌访问 API
curl --cacert ${ CACERT } --header "Authorization: Bearer ${ TOKEN } " -X GET ${ APISERVER } /api
输出类似于:
{
"kind" : "APIVersions" ,
"versions" : [
"v1"
],
"serverAddressByClientCIDRs" : [
{
"clientCIDR" : "0.0.0.0/0" ,
"serverAddress" : "10.0.1.149:443"
}
]
}
4.7.9 - 使用Deployment运行一个无状态应用 本文介绍通过Kubernetes Deployment对象如何去运行一个应用.
教程目标 创建一个 nginx Deployment. 使用 kubectl 列举关于 Deployment 的信息. 更新 Deployment。 准备开始
你必须拥有一个 Kubernetes 的集群,同时你的 Kubernetes 集群必须带有 kubectl 命令行工具。
如果你还没有集群,你可以通过 Minikube 构建一
个你自己的集群,或者你可以使用下面任意一个 Kubernetes 工具构建:
要获知版本信息,请输入
kubectl version.
创建并了解一个 nginx Deployment 你可以通过创建一个 Kubernetes Deployment 对象来运行一个应用, 且你可以在一个
YAML 文件中描述 Deployment。例如, 下面这个 YAML 文件描述了一个运行 nginx:1.14.2
Docker 镜像的 Deployment:
apiVersion : apps/v1
kind : Deployment
metadata :
name : nginx-deployment
spec :
selector :
matchLabels :
app : nginx
replicas : 2 # tells deployment to run 2 pods matching the template
template :
metadata :
labels :
app : nginx
spec :
containers :
- name : nginx
image : nginx:1.14.2
ports :
- containerPort : 80
通过 YAML 文件创建一个 Deployment:
kubectl apply -f https://k8s.io/examples/application/deployment.yaml
显示 Deployment 相关信息:
kubectl describe deployment nginx-deployment
输出类似于这样:
Name: nginx-deployment
Namespace: default
CreationTimestamp: Tue, 30 Aug 2016 18:11:37 -0700
Labels: app=nginx
Annotations: deployment.kubernetes.io/revision=1
Selector: app=nginx
Replicas: 2 desired | 2 updated | 2 total | 2 available | 0 unavailable
StrategyType: RollingUpdate
MinReadySeconds: 0
RollingUpdateStrategy: 1 max unavailable, 1 max surge
Pod Template:
Labels: app=nginx
Containers:
nginx:
Image: nginx:1.7.9
Port: 80/TCP
Environment: <none>
Mounts: <none>
Volumes: <none>
Conditions:
Type Status Reason
---- ------ ------
Available True MinimumReplicasAvailable
Progressing True NewReplicaSetAvailable
OldReplicaSets: <none>
NewReplicaSet: nginx-deployment-1771418926 (2/2 replicas created)
No events.
列出 Deployment 创建的 Pods:
kubectl get pods -l app = nginx
输出类似于这样:
NAME READY STATUS RESTARTS AGE
nginx-deployment-1771418926-7o5ns 1/1 Running 0 16h
nginx-deployment-1771418926-r18az 1/1 Running 0 16h
展示某一个 Pod 信息:
kubectl describe pod <pod-name>
这里的 <pod-name> 是某一 Pod 的名称。
更新 Deployment 你可以通过更新一个新的 YAML 文件来更新 Deployment。下面的 YAML 文件指定该
Deployment 镜像更新为 nginx 1.16.1。
apiVersion : apps/v1
kind : Deployment
metadata :
name : nginx-deployment
spec :
selector :
matchLabels :
app : nginx
replicas : 2
template :
metadata :
labels :
app : nginx
spec :
containers :
- name : nginx
image : nginx:1.16.1 # Update the version of nginx from 1.14.2 to 1.16.1
ports :
- containerPort : 80
应用新的 YAML:
kubectl apply -f https://k8s.io/examples/application/deployment-update.yaml
查看该 Deployment 以新的名称创建 Pods 同时删除旧的 Pods:
kubectl get pods -l app = nginx
通过增加副本数来扩缩应用 你可以通过应用新的 YAML 文件来增加 Deployment 中 Pods 的数量。
下面的 YAML 文件将 replicas 设置为 4,指定该 Deployment 应有 4 个 Pods:
apiVersion : apps/v1
kind : Deployment
metadata :
name : nginx-deployment
spec :
selector :
matchLabels :
app : nginx
replicas : 4 # Update the replicas from 2 to 4
template :
metadata :
labels :
app : nginx
spec :
containers :
- name : nginx
image : nginx:1.14.2
ports :
- containerPort : 80
应用新的 YAML 文件:
kubectl apply -f https://k8s.io/examples/application/deployment-scale.yaml
验证 Deployment 有 4 个 Pods:
kubectl get pods -l app = nginx
输出的结果类似于:
NAME READY STATUS RESTARTS AGE
nginx-deployment-148880595-4zdqq 1/1 Running 0 25s
nginx-deployment-148880595-6zgi1 1/1 Running 0 25s
nginx-deployment-148880595-fxcez 1/1 Running 0 2m
nginx-deployment-148880595-rwovn 1/1 Running 0 2m
删除 Deployment 通过名称删除 Deployment:
kubectl delete deployment nginx-deployment
ReplicationControllers -- 旧的方式 创建一个多副本应用首选方法是使用 Deployment,Deployment 内部使用 ReplicaSet。
在 Deployment 和 ReplicaSet 被引入到 Kubernetes 之前,多副本应用通过
ReplicationController
来配置。
接下来 4.7.10 - 扩缩 StatefulSet 本文介绍如何扩缩StatefulSet。StatefulSet 的扩缩指的是增加或者减少副本个数。
准备开始 StatefulSets 仅适用于 Kubernetes 1.5 及以上版本。
不是所有 Stateful 应用都能很好地执行扩缩操作。
如果你不是很确定是否要扩缩你的 StatefulSet,可先参阅
StatefulSet 概念
或者 StatefulSet 教程 。
仅当你确定你的有状态应用的集群是完全健康的,才可执行扩缩操作.
扩缩 StatefulSet 使用 kubectl 扩缩 StatefulSet 首先,找到你要扩缩的 StatefulSet。
kubectl get statefulsets <statefulset 名称>
更改 StatefulSet 中副本个数:
kubectl scale statefulsets <statefulset 名称> --replicas= <新的副本数>
对 StatefulSet 执行就地更新 另外, 你可以就地更新 StatefulSet。
如果你的 StatefulSet 最初通过 kubectl apply 或 kubectl create --save-config 创建,
你可以更新 StatefulSet 清单中的 .spec.replicas, 然后执行命令 kubectl apply:
kubectl apply -f <更新后的 statefulset 文件>
否则,可以使用 kubectl edit 编辑副本字段:
kubectl edit statefulsets <statefulset 名称>
或者使用 kubectl patch:
kubectl patch statefulsets <statefulset 名称> -p '{"spec":{"replicas":<new-replicas>}}'
故障排查 缩容操作无法正常工作 当 Stateful 所管理的任何 Pod 不健康时,你不能对该 StatefulSet 执行缩容操作。
仅当 StatefulSet 的所有 Pod 都处于运行状态和 Ready 状况后才可缩容.
如果 spec.replicas 大于 1,Kubernetes 无法判定 Pod 不健康的原因。
Pod 不健康可能是由于永久性故障造成也可能是瞬态故障。
瞬态故障可能是节点升级或维护而引起的节点重启造成的。
如果该 Pod 不健康是由于永久性故障导致, 则在不纠正该故障的情况下进行缩容可能会导致
StatefulSet 进入一种状态,其成员 Pod 数量低于应正常运行的副本数。
这种状态也许会导致 StatefulSet 不可用。
如果由于瞬态故障而导致 Pod 不健康并且 Pod 可能再次变为可用,那么瞬态错误可能会干扰
你对 StatefulSet 的扩容/缩容操作。 一些分布式数据库在同时有节点加入和离开时
会遇到问题。在这些情况下,最好是在应用级别进行分析扩缩操作的状态, 并且只有在确保
Stateful 应用的集群是完全健康时才执行扩缩操作。
接下来 4.8 - 运行 Jobs 使用并行处理运行 Jobs。
4.8.1 - 使用 CronJob 运行自动化任务 你可以利用 CronJobs 执行基于时间调度的任务。这些自动化任务和 Linux 或者 Unix 系统的 Cron 任务类似。
CronJobs 在创建周期性以及重复性的任务时很有帮助,例如执行备份操作或者发送邮件。CronJobs 也可以在特定时间调度单个任务,例如你想调度低活跃周期的任务。
CronJobs 有一些限制和特点。
例如,在特定状况下,同一个 CronJob 可以创建多个任务。
因此,任务应该是幂等的。
查看更多限制,请参考 CronJobs 。
准备开始 创建 CronJob CronJob 需要一个配置文件。
本例中 CronJob 的.spec 配置文件每分钟打印出当前时间和一个问好信息:
apiVersion : batch/v1beta1
kind : CronJob
metadata :
name : hello
spec :
schedule : "*/1 * * * *"
jobTemplate :
spec :
template :
spec :
containers :
- name : hello
image : busybox
imagePullPolicy : IfNotPresent
command :
- /bin/sh
- -c
- date; echo Hello from the Kubernetes cluster
restartPolicy : OnFailure
想要运行示例的 CronJob,可以下载示例文件并执行命令:
kubectl create -f https://k8s.io/examples/application/job/cronjob.yaml
cronjob.batch/hello created
创建好 CronJob 后,使用下面的命令来获取其状态:
kubectl get cronjob hello
输出类似于:
NAME SCHEDULE SUSPEND ACTIVE LAST SCHEDULE AGE
hello */1 * * * * False 0 50s 75s
就像你从命令返回结果看到的那样,CronJob 还没有调度或执行任何任务。大约需要一分钟任务才能创建好。
NAME COMPLETIONS DURATION AGE
hello-4111706356 0/1 0s
hello-4111706356 0/1 0s 0s
hello-4111706356 1/1 5s 5s
现在你已经看到了一个运行中的任务被 “hello” CronJob 调度。
你可以停止监视这个任务,然后再次查看 CronJob 就能看到它调度任务:
kubectl get cronjob hello
输出类似于:
NAME SCHEDULE SUSPEND ACTIVE LAST SCHEDULE AGE
hello */1 * * * * False 0 50s 75s
你应该能看到 “hello” CronJob 在 LAST-SCHEDULE 声明的时间点成功的调度了一次任务。
有 0 个活跃的任务意味着任务执行完毕或者执行失败。
现在,找到最后一次调度任务创建的 Pod 并查看一个 Pod 的标准输出。请注意任务名称和 Pod 名称是不同的。
说明: Job 名称和 Pod 名称不同。
# 在你的系统上将 "hello-4111706356" 替换为 Job 名称
pods = $( kubectl get pods --selector= job-name= hello-4111706356 --output= jsonpath ={ .items..metadata.name} )
查看 Pod 日志:
Fri Feb 22 11:02:09 UTC 2019
Hello from the Kubernetes cluster
删除 CronJob 当你不再需要 CronJob 时,可以用 kubectl delete cronjob <cronjob name> 删掉它:
kubectl delete cronjob hello
删除 CronJob 会清除它创建的所有任务和 Pod,并阻止它创建额外的任务。你可以查阅
垃圾收集 。
编写 CronJob 声明信息 像 Kubernetes 的其他配置一样,CronJob 需要 apiVersion、kind、和 metadata 域。
配置文件的一般信息,请参考
部署应用 和
使用 kubectl 管理资源 .
CronJob 配置也需要包括
.spec .
说明: 对 CronJob 的所有改动,特别是它的 .spec,只会影响将来的运行实例。
时间安排 .spec.schedule 是 .spec 需要的域。它使用了 Cron
格式串,例如 0 * * * * or @hourly ,做为它的任务被创建和执行的调度时间。
该格式也包含了扩展的 vixie cron 步长值。
FreeBSD 手册 中解释如下:
步长可被用于范围组合。范围后面带有 /<数字> 可以声明范围内的步幅数值。
例如,0-23/2 可被用在小时域来声明命令在其他数值的小时数执行
( V7 标准中对应的方法是0,2,4,6,8,10,12,14,16,18,20,22)。
步长也可以放在通配符后面,因此如果你想表达 "每两小时",就用 */2 。
说明: 调度中的问号 (?) 和星号 * 含义相同,表示给定域的任何可用值。
任务模版 .spec.jobTemplate是任务的模版,它是必须的。它和
Job 的语法完全一样,
除了它是嵌套的没有 apiVersion 和 kind。
编写任务的 .spec ,请参考
编写 Job 的Spec 。
开始的最后期限 .spec.startingDeadlineSeconds 域是可选的。
它表示任务如果由于某种原因错过了调度时间,开始该任务的截止时间的秒数。过了截止时间,CronJob 就不会开始任务。
不满足这种最后期限的任务会被统计为失败任务。如果该域没有声明,那任务就没有最后期限。
CronJob 控制器会统计错过了多少次调度。如果错过了100次以上的调度,CronJob 就不再调度了。
当没有设置 .spec.startingDeadlineSeconds 时,CronJob 控制器统计从
status.lastScheduleTime 到当前的调度错过次数。
例如一个 CronJob 期望每分钟执行一次,status.lastScheduleTime是 5:00am,
但现在是 7:00am。那意味着 120 次调度被错过了,所以 CronJob 将不再被调度。
如果设置了 .spec.startingDeadlineSeconds 域(非空),CronJob 控制器统计从
.spec.startingDeadlineSeconds 到当前时间错过了多少次任务。
例如设置了 200,它会统计过去 200 秒内错过了多少次调度。
在那种情况下,如果过去 200 秒内错过了超过 100 次的调度,CronJob 就不再调度。
并发性规则 .spec.concurrencyPolicy 也是可选的。它声明了 CronJob 创建的任务执行时发生重叠如何处理。
spec 仅能声明下列规则中的一种:
Allow (默认):CronJob 允许并发任务执行。Forbid: CronJob 不允许并发任务执行;如果新任务的执行时间到了而老任务没有执行完,CronJob 会忽略新任务的执行。Replace:如果新任务的执行时间到了而老任务没有执行完,CronJob 会用新任务替换当前正在运行的任务。请注意,并发性规则仅适用于相同 CronJob 创建的任务。如果有多个 CronJob,它们相应的任务总是允许并发执行的。
挂起 .spec.suspend域也是可选的。如果设置为 true ,后续发生的执行都会挂起。
这个设置对已经开始的执行不起作用。默认是关闭的。
注意: 在调度时间内挂起的执行都会被统计为错过的任务。当
.spec.suspend 从
true 改为
false 时,
且没有
开始的最后期限 ,错过的任务会被立即调度。
任务历史限制 .spec.successfulJobsHistoryLimit 和 .spec.failedJobsHistoryLimit是可选的。
这两个字段指定应保留多少已完成和失败的任务。
默认设置为3和1。限制设置为0代表相应类型的任务完成后不会保留。
4.8.2 - 使用展开的方式进行并行处理 本任务展示基于一个公共的模板运行多个Jobs 。
你可以用这种方法来并行执行批处理任务。
在本任务示例中,只有三个工作条目:apple 、banana 和 cherry 。
示例任务处理每个条目时仅仅是打印一个字符串之后结束。
参考在真实负载中使用 Job 了解更适用于真实使用场景的模式。
准备开始 你应先熟悉基本的、非并行的 Job
的用法。
你必须拥有一个 Kubernetes 的集群,同时你的 Kubernetes 集群必须带有 kubectl 命令行工具。
如果你还没有集群,你可以通过 Minikube 构建一
个你自己的集群,或者你可以使用下面任意一个 Kubernetes 工具构建:
任务中的基本模板示例要求安装命令行工具 sed。
要使用较高级的模板示例,你需要安装 Python ,
并且要安装 Jinja2 模板库。
一旦 Python 已经安装好,你可以运行下面的命令安装 Jinja2:
pip install --user jinja2
基于模板创建 Job 首先,将以下作业模板下载到名为 job-tmpl.yaml 的文件中。
apiVersion : batch/v1
kind : Job
metadata :
name : process-item-$ITEM
labels :
jobgroup : jobexample
spec :
template :
metadata :
name : jobexample
labels :
jobgroup : jobexample
spec :
containers :
- name : c
image : busybox
command : ["sh" , "-c" , "echo Processing item $ITEM && sleep 5" ]
restartPolicy : Never
# 使用 curl 下载 job-tmpl.yaml
curl -L -s -O https://k8s.io/examples/application/job/job-tmpl.yaml
你所下载的文件不是一个合法的 Kubernetes 清单 。
这里的模板只是 Job 对象的 yaml 表示,其中包含一些占位符,在使用它之前需要被填充。
$ITEM 语法对 Kubernetes 没有意义。
基于模板创建清单 下面的 Shell 代码片段使用 sed 将字符串 $ITEM 替换为循环变量,并将结果
写入到一个名为 jobs 的临时目录。
# 展开模板文件到多个文件中,每个文件对应一个要处理的条目
mkdir ./jobs
for i in apple banana cherry
do
cat job-tmpl.yaml | sed "s/\$ITEM/ $i /" > ./jobs/job-$i .yaml
done
检查上述脚本的输出:
输出类似于:
job-apple.yaml
job-banana.yaml
job-cherry.yaml
你可以使用任何一种模板语言(例如:Jinja2、ERB),或者编写一个程序来
生成 Job 清单。
基于清单创建 Job 接下来用一个 kubectl 命令创建所有的 Job:
输出类似于:
job.batch/process-item-apple created
job.batch/process-item-banana created
job.batch/process-item-cherry created
现在检查 Job:
kubectl get jobs -l jobgroup = jobexample
输出类似于:
NAME COMPLETIONS DURATION AGE
process-item-apple 1/1 14s 22s
process-item-banana 1/1 12s 21s
process-item-cherry 1/1 12s 20s
使用 kubectl 的 -l 选项可以仅选择属于当前 Job 组的对象
(系统中可能存在其他不相关的 Job)。
你可以使用相同的 标签选择算符
来过滤 Pods:
kubectl get pods -l jobgroup = jobexample
输出类似于:
NAME READY STATUS RESTARTS AGE
process-item-apple-kixwv 0/1 Completed 0 4m
process-item-banana-wrsf7 0/1 Completed 0 4m
process-item-cherry-dnfu9 0/1 Completed 0 4m
我们可以用下面的命令查看所有 Job 的输出:
kubectl logs -f -l jobgroup = jobexample
输出类似于:
Processing item apple
Processing item banana
Processing item cherry
清理 # 删除所创建的 Job
# 集群会自动清理 Job 对应的 Pod
kubectl delete job -l jobgroup = jobexample
使用高级模板参数 在第一个例子 中,模板的每个示例都有一个参数
而该参数也用在 Job 名称中。不过,对象
名称
被限制只能使用某些字符。
这里的略微复杂的例子使用 Jinja 模板语言
来生成清单,并基于清单来生成对象,每个 Job 都有多个参数。
在本任务中,你将会使用一个一行的 Python 脚本,将模板转换为一组清单文件。
首先,复制下面的 Job 对象模板到一个名为 job.yaml.jinja2 的文件。
{%- set params = [{ "name": "apple", "url": "http://dbpedia.org/resource/Apple", },
{ "name": "banana", "url": "http://dbpedia.org/resource/Banana", },
{ "name": "cherry", "url": "http://dbpedia.org/resource/Cherry" }]
%}
{%- for p in params %}
{%- set name = p["name"] %}
{%- set url = p["url"] %}
---
apiVersion: batch/v1
kind: Job
metadata:
name: jobexample-{{ name }}
labels:
jobgroup: jobexample
spec:
template:
metadata:
name: jobexample
labels:
jobgroup: jobexample
spec:
containers:
- name: c
image: busybox
command: ["sh", "-c", "echo Processing URL {{ url }} && sleep 5"]
restartPolicy: Never
{%- endfor %}
上面的模板使用 python 字典列表(第 1-4 行)定义每个作业对象的参数。
然后使用 for 循环为每组参数(剩余行)生成一个作业 yaml 对象。
我们利用了多个 YAML 文档(这里的 Kubernetes 清单)可以用 --- 分隔符连接的事实。
我们可以将输出直接传递给 kubectl 来创建对象。
接下来我们用单行的 Python 程序将模板展开。
alias render_template = 'python -c "from jinja2 import Template; import sys; print(Template(sys.stdin.read()).render());"'
使用 render_template 将参数和模板转换成一个 YAML 文件,其中包含 Kubernetes
资源清单:
# 此命令需要之前定义的别名
cat job.yaml.jinja2 | render_template > jobs.yaml
你可以查看 jobs.yaml 以验证 render_template 脚本是否正常工作。
当你对输出结果比较满意时,可以用管道将其输出发送给 kubectl,如下所示:
cat job.yaml.jinja2 | render_template | kubectl apply -f -
Kubernets 接收清单文件并执行你所创建的 Job。
清理 # 删除所创建的 Job
# 集群会自动清理 Job 对应的 Pod
kubectl delete job -l jobgroup = jobexample
在真实负载中使用 Job 在真实的负载中,每个 Job 都会执行一些重要的计算,例如渲染电影的一帧,
或者处理数据库中的若干行。这时,$ITEM 参数将指定帧号或行范围。
在此任务中,你运行一个命令通过取回 Pod 的日志来收集其输出。
在真实应用场景中,Job 的每个 Pod 都会在结束之前将其输出写入到某持久性存储中。
你可以为每个 Job 指定 PersistentVolume 卷,或者使用其他外部存储服务。
例如,如果你在渲染视频帧,你可能会使用 HTTP 协议将渲染完的帧数据
用 'PUT' 请求发送到某 URL,每个帧使用不同的 URl。
Job 和 Pod 上的标签 你创建了 Job 之后,Kubernetes 自动为 Job 的 Pod 添加
标签 ,以便能够将一个 Job
的 Pod 与另一个 Job 的 Pod 区分开来。
在本例中,每个 Job 及其 Pod 模板有一个标签: jobgroup=jobexample。
Kubernetes 自身对标签名 jobgroup 没有什么要求。
为创建自同一模板的所有 Job 使用同一标签使得我们可以方便地同时操作组中的所有作业。
在第一个例子 中,你使用模板来创建了若干 Job。
模板确保每个 Pod 都能够获得相同的标签,这样你可以用一条命令检查这些模板化
Job 所生成的全部 Pod。
说明: 标签键
jobgroup 没什么特殊的,也不是保留字。 你可以选择你自己的标签方案。
如果愿意,有一些
建议的标签
可供使用。
替代方案 如果你有计划创建大量 Job 对象,你可能会发现:
即使使用标签,管理这么多 Job 对象也很麻烦。 如果你一次性创建很多 Job,很可能会给 Kubernetes 控制面带来很大压力。
一种替代方案是,Kubernetes API 可能对请求施加速率限制,通过 429 返回
状态值临时拒绝你的请求。 你可能会受到 Job 相关的资源配额
限制:如果你在一个批量请求中触发了太多的任务,API 服务器会永久性地拒绝你的某些请求。 还有一些其他作业模式
可供选择,这些模式都能用来处理大量任务而又不会创建过多的 Job 对象。
你也可以考虑编写自己的控制器
来自动管理 Job 对象。
4.8.3 - 使用工作队列进行粗粒度并行处理 本例中,我们会运行包含多个并行工作进程的 Kubernetes Job。
本例中,每个 Pod 一旦被创建,会立即从任务队列中取走一个工作单元并完成它,然后将工作单元从队列中删除后再退出。
下面是本次示例的主要步骤:
启动一个消息队列服务 本例中,我们使用 RabbitMQ,你也可以用其他的消息队列服务。在实际工作环境中,你可以创建一次消息队列服务然后在多个任务中重复使用。
创建一个队列,放上消息数据 每个消息表示一个要执行的任务。本例中,每个消息是一个整数值。我们将基于这个整数值执行很长的计算操作。
启动一个在队列中执行这些任务的 Job 。该 Job 启动多个 Pod。每个 Pod 从消息队列中取走一个任务,处理它,然后重复执行,直到队列的队尾。
准备开始 要熟悉 Job 基本用法(非并行的),请参考
Job 。
你必须拥有一个 Kubernetes 的集群,同时你的 Kubernetes 集群必须带有 kubectl 命令行工具。
如果你还没有集群,你可以通过 Minikube 构建一
个你自己的集群,或者你可以使用下面任意一个 Kubernetes 工具构建:
您的 Kubernetes 服务器版本必须不低于版本 v1.8.
要获知版本信息,请输入
kubectl version.
启动消息队列服务 本例使用了 RabbitMQ,使用其他 AMQP 类型的消息服务应该比较容易。
在实际工作中,在集群中一次性部署某个消息队列服务,之后在很多 Job 中复用,包括需要长期运行的服务。
按下面的方法启动 RabbitMQ:
kubectl create -f https://raw.githubusercontent.com/kubernetes/kubernetes/release-1.3/examples/celery-rabbitmq/rabbitmq-service.yaml
service "rabbitmq-service" created
kubectl create -f https://raw.githubusercontent.com/kubernetes/kubernetes/release-1.3/examples/celery-rabbitmq/rabbitmq-controller.yaml
replicationcontroller "rabbitmq-controller" created
我们仅用到 celery-rabbitmq 示例 中描述的部分功能。
测试消息队列服务 现在,我们可以试着访问消息队列。我们将会创建一个临时的可交互的 Pod,在它上面安装一些工具,然后用队列做实验。
首先创建一个临时的可交互的 Pod:
# 创建一个临时的可交互的 Pod
kubectl run -i --tty temp --image ubuntu:14.04
Waiting for pod default/temp-loe07 to be running, status is Pending, pod ready: false
... [ previous line repeats several times .. hit return when it stops ] ...
请注意你的 Pod 名称和命令提示符将会不同。
接下来安装 amqp-tools ,这样我们就能用消息队列了。
# 安装一些工具
root@temp-loe07:/# apt-get update
.... [ lots of output ] ....
root@temp-loe07:/# apt-get install -y curl ca-certificates amqp-tools python dnsutils
.... [ lots of output ] ....
后续,我们将制作一个包含这些包的 Docker 镜像。
接着,我们将要验证我们发现 RabbitMQ 服务:
# 请注意 rabbitmq-service 有Kubernetes 提供的 DNS 名称,
root@temp-loe07:/# nslookup rabbitmq-service
Server: 10.0.0.10
Address: 10.0.0.10#53
Name: rabbitmq-service.default.svc.cluster.local
Address: 10.0.147.152
# 你的 IP 地址会不同
如果 Kube-DNS 没有正确安装,上一步可能会出错。
你也可以在环境变量中找到服务 IP。
# env | grep RABBIT | grep HOST
RABBITMQ_SERVICE_SERVICE_HOST=10.0.147.152
# 你的 IP 地址会有所不同
接着我们将要确认可以创建队列,并能发布消息和消费消息。
# 下一行,rabbitmq-service 是访问 rabbitmq-service 的主机名。5672是 rabbitmq 的标准端口。
root@temp-loe07:/# export BROKER_URL = amqp://guest:guest@rabbitmq-service:5672
# 如果上一步中你不能解析 "rabbitmq-service",可以用下面的命令替换:
# root@temp-loe07:/# BROKER_URL=amqp://guest:guest@$RABBITMQ_SERVICE_SERVICE_HOST:5672
# 现在创建队列:
root@temp-loe07:/# /usr/bin/amqp-declare-queue --url= $BROKER_URL -q foo -d foo
# 向它推送一条消息:
root@temp-loe07:/# /usr/bin/amqp-publish --url= $BROKER_URL -r foo -p -b Hello
# 然后取回它.
root@temp-loe07:/# /usr/bin/amqp-consume --url= $BROKER_URL -q foo -c 1 cat && echo
Hello
root@temp-loe07:/#
最后一个命令中, amqp-consume 工具从队列中取走了一个消息,并把该消息传递给了随机命令的标准输出。在这种情况下,cat 只会打印它从标准输入或得的内容,echo 只会添加回车符以便示例可读。
为队列增加任务 现在让我们给队列增加一些任务。在我们的示例中,任务是多个待打印的字符串。
实践中,消息的内容可以是:
待处理的文件名 程序额外的参数 数据库表的关键字范围 模拟任务的配置参数 待渲染的场景的帧序列号 本例中,如果有大量的数据需要被 Job 的所有 Pod 读取,典型的做法是把它们放在一个共享文件系统中,如NFS,并以只读的方式挂载到所有 Pod,或者 Pod 中的程序从类似 HDFS 的集群文件系统中读取。
例如,我们创建队列并使用 amqp 命令行工具向队列中填充消息。实践中,你可以写个程序来利用 amqp 客户端库来填充这些队列。
/usr/bin/amqp-declare-queue --url= $BROKER_URL -q job1 -d job1
for f in apple banana cherry date fig grape lemon melon
do
/usr/bin/amqp-publish --url= $BROKER_URL -r job1 -p -b $f
done
这样,我们给队列中填充了8个消息。
创建镜像 现在我们可以创建一个做为 Job 来运行的镜像。
我们将用 amqp-consume 来从队列中读取消息并实际运行我们的程序。这里给出一个非常简单的示例程序:
#!/usr/bin/env python
# Just prints standard out and sleeps for 10 seconds.
import sys
import time
print ("Processing " + sys. stdin. readlines()[0 ])
time. sleep(10 )
现在,编译镜像。如果你在用源代码树,那么切换到目录 examples/job/work-queue-1。
否则的话,创建一个临时目录,切换到这个目录。下载
Dockerfile ,和
worker.py 。
无论哪种情况,都可以用下面的命令编译镜像
docker build -t job-wq-1 .
对于 Docker Hub , 给你的应用镜像打上标签,
标签为你的用户名,然后用下面的命令推送到 Hub。用你的 Hub 用户名替换 <username>。
docker tag job-wq-1 <username>/job-wq-1
docker push <username>/job-wq-1
如果你在用谷歌容器仓库 ,
用你的项目 ID 作为标签打到你的应用镜像上,然后推送到 GCR。
用你的项目 ID 替换 <project>。
docker tag job-wq-1 gcr.io/<project>/job-wq-1
gcloud docker -- push gcr.io/<project>/job-wq-1
定义 Job 这里给出一个 Job 定义 yaml文件。你需要拷贝一份并编辑镜像以匹配你使用的名称,保存为 ./job.yaml。
apiVersion : batch/v1
kind : Job
metadata :
name : job-wq-1
spec :
completions : 8
parallelism : 2
template :
metadata :
name : job-wq-1
spec :
containers :
- name : c
image : gcr.io/<project>/job-wq-1
env :
- name : BROKER_URL
value : amqp://guest:guest@rabbitmq-service:5672
- name : QUEUE
value : job1
restartPolicy : OnFailure
本例中,每个 Pod 使用队列中的一个消息然后退出。这样,Job 的完成计数就代表了完成的工作项的数量。本例中我们设置 .spec.completions: 8,因为我们放了8项内容在队列中。
运行 Job 现在我们运行 Job:
kubectl create -f ./job.yaml
稍等片刻,然后检查 Job。
kubectl describe jobs/job-wq-1
Name: job-wq-1
Namespace: default
Selector: controller-uid=41d75705-92df-11e7-b85e-fa163ee3c11f
Labels: controller-uid=41d75705-92df-11e7-b85e-fa163ee3c11f
job-name=job-wq-1
Annotations: <none>
Parallelism: 2
Completions: 8
Start Time: Wed, 06 Sep 2017 16:42:02 +0800
Pods Statuses: 0 Running / 8 Succeeded / 0 Failed
Pod Template:
Labels: controller-uid=41d75705-92df-11e7-b85e-fa163ee3c11f
job-name=job-wq-1
Containers:
c:
Image: gcr.io/causal-jigsaw-637/job-wq-1
Port:
Environment:
BROKER_URL: amqp://guest:guest@rabbitmq-service:5672
QUEUE: job1
Mounts: <none>
Volumes: <none>
Events:
FirstSeen LastSeen Count From SubobjectPath Type Reason Message
───────── ──────── ───── ──── ───────────── ────── ────── ───────
27s 27s 1 {job } Normal SuccessfulCreate Created pod: job-wq-1-hcobb
27s 27s 1 {job } Normal SuccessfulCreate Created pod: job-wq-1-weytj
27s 27s 1 {job } Normal SuccessfulCreate Created pod: job-wq-1-qaam5
27s 27s 1 {job } Normal SuccessfulCreate Created pod: job-wq-1-b67sr
26s 26s 1 {job } Normal SuccessfulCreate Created pod: job-wq-1-xe5hj
15s 15s 1 {job } Normal SuccessfulCreate Created pod: job-wq-1-w2zqe
14s 14s 1 {job } Normal SuccessfulCreate Created pod: job-wq-1-d6ppa
14s 14s 1 {job } Normal SuccessfulCreate Created pod: job-wq-1-p17e0
我们所有的 Pod 都成功了。耶!
替代方案 本文所讲述的处理方法的好处是你不需要修改你的 "worker" 程序使其知道工作队列的存在。
本文所描述的方法需要你运行一个消息队列服务。如果不方便运行消息队列服务,你也许会考虑另外一种
任务模式 。
本文所述的方法为每个工作项创建了一个 Pod。
如果你的工作项仅需数秒钟,为每个工作项创建 Pod会增加很多的常规消耗。
可以考虑另外的方案请参考示例 ,
这种方案可以实现每个 Pod 执行多个工作项。
示例中,我们使用 amqp-consume 从消息队列读取消息并执行我们真正的程序。
这样的好处是你不需要修改你的程序使其知道队列的存在。
要了解怎样使用客户端库和工作队列通信,请参考
不同的示例 。
友情提醒 如果设置的完成数量小于队列中的消息数量,会导致一部分消息项不会被执行。
如果设置的完成数量大于队列中的消息数量,当队列中所有的消息都处理完成后,
Job 也会显示为未完成。Job 将创建 Pod 并阻塞等待消息输入。
当发生下面两种情况时,即使队列中所有的消息都处理完了,Job 也不会显示为完成状态:
在 amqp-consume 命令拿到消息和容器成功退出之间的时间段内,执行杀死容器操作; 在 kubelet 向 api-server 传回 Pod 成功运行之前,发生节点崩溃。 4.8.4 - 使用工作队列进行精细的并行处理 在这个例子中,我们会运行一个Kubernetes Job,其中的 Pod 会运行多个并行工作进程。
在这个例子中,当每个pod被创建时,它会从一个任务队列中获取一个工作单元,处理它,然后重复,直到到达队列的尾部。
下面是这个示例的步骤概述:
启动存储服务用于保存工作队列。 在这个例子中,我们使用 Redis 来存储工作项。
在上一个例子中,我们使用了 RabbitMQ。
在这个例子中,由于 AMQP 不能为客户端提供一个良好的方法来检测一个有限长度的工作队列是否为空,
我们使用了 Redis 和一个自定义的工作队列客户端库。
在实践中,你可能会设置一个类似于 Redis 的存储库,并将其同时用于多项任务或其他事务的工作队列。创建一个队列,然后向其中填充消息。 每个消息表示一个将要被处理的工作任务。
在这个例子中,消息只是一个我们将用于进行长度计算的整数。启动一个 Job 对队列中的任务进行处理 。这个 Job 启动了若干个 Pod 。
每个 Pod 从消息队列中取出一个工作任务,处理它,然后重复,直到到达队列的尾部。准备开始
你必须拥有一个 Kubernetes 的集群,同时你的 Kubernetes 集群必须带有 kubectl 命令行工具。
如果你还没有集群,你可以通过 Minikube 构建一
个你自己的集群,或者你可以使用下面任意一个 Kubernetes 工具构建:
您的 Kubernetes 服务器版本必须不低于版本 v1.8.
要获知版本信息,请输入
kubectl version.
熟悉基本的、非并行的 Job 。
启动 Redis 对于这个例子,为了简单起见,我们将启动一个单实例的 Redis。
了解如何部署一个可伸缩、高可用的 Redis 例子,请查看
Redis 示例
你也可以直接下载如下文件:
使用任务填充队列 现在,让我们往队列里添加一些“任务”。在这个例子中,我们的任务只是一些将被打印出来的字符串。
启动一个临时的可交互的 pod 用于运行 Redis 命令行界面。
kubectl run -i --tty temp --image redis --command "/bin/sh"
Waiting for pod default/redis2-c7h78 to be running, status is Pending, pod ready: false
Hit enter for command prompt
现在按回车键,启动 redis 命令行界面,然后创建一个存在若干个工作项的列表。
# redis-cli -h redis
redis:6379> rpush job2 "apple"
( integer) 1
redis:6379> rpush job2 "banana"
( integer) 2
redis:6379> rpush job2 "cherry"
( integer) 3
redis:6379> rpush job2 "date"
( integer) 4
redis:6379> rpush job2 "fig"
( integer) 5
redis:6379> rpush job2 "grape"
( integer) 6
redis:6379> rpush job2 "lemon"
( integer) 7
redis:6379> rpush job2 "melon"
( integer) 8
redis:6379> rpush job2 "orange"
( integer) 9
redis:6379> lrange job2 0 -1
1) "apple"
2) "banana"
3) "cherry"
4) "date"
5) "fig"
6) "grape"
7) "lemon"
8) "melon"
9) "orange"
因此,这个键为 job2 的列表就是我们的工作队列。
注意:如果你还没有正确地配置 Kube DNS,你可能需要将上面的第一步改为
redis-cli -h $REDIS_SERVICE_HOST。
创建镜像 现在我们已经准备好创建一个我们要运行的镜像
我们会使用一个带有 redis 客户端的 python 工作程序从消息队列中读出消息。
这里提供了一个简单的 Redis 工作队列客户端库,叫 rediswq.py (下载 )。
Job 中每个 Pod 内的 “工作程序” 使用工作队列客户端库获取工作。如下:
#!/usr/bin/env python
import time
import rediswq
host= "redis"
# Uncomment next two lines if you do not have Kube-DNS working.
# import os
# host = os.getenv("REDIS_SERVICE_HOST")
q = rediswq. RedisWQ(name= "job2" , host= "redis" )
print ("Worker with sessionID: " + q. sessionID())
print ("Initial queue state: empty=" + str (q. empty()))
while not q. empty():
item = q. lease(lease_secs= 10 , block= True, timeout= 2 )
if item is not None:
itemstr = item. decode("utf-8" )
print ("Working on " + itemstr)
time. sleep(10 ) # Put your actual work here instead of sleep.
q. complete(item)
else :
print ("Waiting for work" )
print ("Queue empty, exiting" )
你也可以下载 worker.py 、
rediswq.py 和
Dockerfile 。然后构建镜像:
docker build -t job-wq-2 .
Push 镜像 对于 Docker Hub ,请先用你的用户名给镜像打上标签,
然后使用下面的命令 push 你的镜像到仓库。请将 <username> 替换为你自己的 Hub 用户名。
docker tag job-wq-2 <username>/job-wq-2
docker push <username>/job-wq-2
你需要将镜像 push 到一个公共仓库或者
配置集群访问你的私有仓库 。
如果你使用的是 Google Container Registry ,
请先用你的 project ID 给你的镜像打上标签,然后 push 到 GCR 。请将 <project> 替换为你自己的 project ID
docker tag job-wq-2 gcr.io/<project>/job-wq-2
gcloud docker -- push gcr.io/<project>/job-wq-2
定义一个 Job 这是 job 定义:
apiVersion : batch/v1
kind : Job
metadata :
name : job-wq-2
spec :
parallelism : 2
template :
metadata :
name : job-wq-2
spec :
containers :
- name : c
image : gcr.io/myproject/job-wq-2
restartPolicy : OnFailure
请确保将 job 模板中的 gcr.io/myproject 更改为你自己的路径。
在这个例子中,每个 pod 处理了队列中的多个项目,直到队列中没有项目时便退出。
因为是由工作程序自行检测工作队列是否为空,并且 Job 控制器不知道工作队列的存在,
这依赖于工作程序在完成工作时发出信号。
工作程序以成功退出的形式发出信号表示工作队列已经为空。
所以,只要有任意一个工作程序成功退出,控制器就知道工作已经完成了,所有的 Pod 将很快会退出。
因此,我们将 Job 的完成计数(Completion Count)设置为 1 。
尽管如此,Job 控制器还是会等待其它 Pod 完成。
运行 Job 现在运行这个 Job :
kubectl apply -f ./job.yaml
稍等片刻,然后检查这个 Job。
kubectl describe jobs/job-wq-2
Name: job-wq-2
Namespace: default
Selector: controller-uid=b1c7e4e3-92e1-11e7-b85e-fa163ee3c11f
Labels: controller-uid=b1c7e4e3-92e1-11e7-b85e-fa163ee3c11f
job-name=job-wq-2
Annotations: <none>
Parallelism: 2
Completions: <unset>
Start Time: Mon, 11 Jan 2016 17:07:59 -0800
Pods Statuses: 1 Running / 0 Succeeded / 0 Failed
Pod Template:
Labels: controller-uid=b1c7e4e3-92e1-11e7-b85e-fa163ee3c11f
job-name=job-wq-2
Containers:
c:
Image: gcr.io/exampleproject/job-wq-2
Port:
Environment: <none>
Mounts: <none>
Volumes: <none>
Events:
FirstSeen LastSeen Count From SubobjectPath Type Reason Message
--------- -------- ----- ---- ------------- -------- ------ -------
33s 33s 1 {job-controller } Normal SuccessfulCreate Created pod: job-wq-2-lglf8
查看日志:
kubectl logs pods/job-wq-2-7r7b2
Worker with sessionID: bbd72d0a-9e5c-4dd6-abf6-416cc267991f
Initial queue state: empty=False
Working on banana
Working on date
Working on lemon
你可以看到,其中的一个 pod 处理了若干个工作单元。
替代方案 如果你不方便运行一个队列服务或者修改你的容器用于运行一个工作队列,你可以考虑其它的
Job 模式 。
如果你有持续的后台处理业务,那么可以考虑使用 ReplicaSet 来运行你的后台业务,
和运行一个类似 https://github.com/resque/resque
的后台处理库。
4.9 - 访问集群中的应用程序 配置负载平衡、端口转发或设置防火墙或 DNS 配置,以访问集群中的应用程序。
4.9.1 - Web 界面 (Dashboard) Dashboard 是基于网页的 Kubernetes 用户界面。
你可以使用 Dashboard 将容器应用部署到 Kubernetes 集群中,也可以对容器应用排错,还能管理集群资源。
你可以使用 Dashboard 获取运行在集群中的应用的概览信息,也可以创建或者修改 Kubernetes 资源
(如 Deployment,Job,DaemonSet 等等)。
例如,你可以对 Deployment 实现弹性伸缩、发起滚动升级、重启 Pod 或者使用向导创建新的应用。
Dashboard 同时展示了 Kubernetes 集群中的资源状态信息和所有报错信息。
部署 Dashboard UI 默认情况下不会部署 Dashboard。可以通过以下命令部署:
kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.0.0/aio/deploy/recommended.yaml
访问 Dashboard UI 为了保护你的集群数据,默认情况下,Dashboard 会使用最少的 RBAC 配置进行部署。
当前,Dashboard 仅支持使用 Bearer 令牌登录。
要为此样本演示创建令牌,你可以按照
创建示例用户
上的指南进行操作。
警告: 在教程中创建的样本用户将具有管理特权,并且仅用于教育目的。
命令行代理 你可以使用 kubectl 命令行工具访问 Dashboard,命令如下:
kubectl proxy
kubectl 会使得 Dashboard 可以通过 http://localhost:8001/api/v1/namespaces/kubernetes-dashboard/services/https:kubernetes-dashboard:/proxy/ 访问。
UI 只能 通过执行这条命令的机器进行访问。更多选项参见 kubectl proxy --help。
说明: Kubeconfig 身份验证方法不支持外部身份提供程序或基于 x509 证书的身份验证。
欢迎界面 当访问空集群的 Dashboard 时,你会看到欢迎界面。
页面包含一个指向此文档的链接,以及一个用于部署第一个应用程序的按钮。
此外,你可以看到在默认情况下有哪些默认系统应用运行在 kube-system
名字空间 中,比如 Dashboard 自己。
部署容器化应用 通过一个简单的部署向导,你可以使用 Dashboard 将容器化应用作为一个 Deployment 和可选的 Service 进行创建和部署。可以手工指定应用的详细配置,或者上传一个包含应用配置的 YAML 或 JSON 文件。
点击任何页面右上角的 CREATE 按钮以开始。
指定应用的详细配置 部署向导需要你提供以下信息:
容器镜像 (必填):公共镜像仓库上的 Docker
容器镜像 或者私有镜像仓库
(通常是 Google Container Registery 或者 Docker Hub)的 URL。容器镜像参数说明必须以冒号结尾。服务 (可选):对于部分应用(比如前端),你可能想对外暴露一个
Service ,这个 Service
可能用的是集群之外的公网 IP 地址(外部 Service)。
说明: 对于外部服务,你可能需要开放一个或多个端口才行。
其它只能对集群内部可见的 Service 称为内部 Service。
不管哪种 Service 类型,如果你选择创建一个 Service,而且容器在一个端口上开启了监听(入向的),
那么你需要定义两个端口。创建的 Service 会把(入向的)端口映射到容器可见的目标端口。
该 Service 会把流量路由到你部署的 Pod。支持的协议有 TCP 和 UDP。
这个 Service 的内部 DNS 解析名就是之前你定义的应用名称的值。
如果需要,你可以打开 Advanced Options 部分,这里你可以定义更多设置:
描述 :这里你输入的文本会作为一个
注解
添加到 Deployment,并显示在应用的详细信息中。名字空间 :Kubernetes 支持多个虚拟集群依附于同一个物理集群。
这些虚拟集群被称为
名字空间 ,
可以让你将资源划分为逻辑命名的组。
Dashboard 通过下拉菜单提供所有可用的名字空间,并允许你创建新的名字空间。
名字空间的名称最长可以包含 63 个字母或数字和中横线(-),但是不能包含大写字母。
名字空间的名称不能只包含数字。如果名字被设置成一个数字,比如 10,pod 就
在名字空间创建成功的情况下,默认会使用新创建的名字空间。如果创建失败,那么第一个名字空间会被选中。
镜像拉取 Secret :如果要使用私有的 Docker 容器镜像,需要拉取
Secret 凭证。
Dashboard 通过下拉菜单提供所有可用的 Secret,并允许你创建新的 Secret。
Secret 名称必须遵循 DNS 域名语法,比如 new.image-pull.secret。
Secret 的内容必须是 base64 编码的,并且在一个
.dockercfg
文件中声明。Secret 名称最大可以包含 253 个字符。
在镜像拉取 Secret 创建成功的情况下,默认会使用新创建的 Secret。
如果创建失败,则不会使用任何 Secret。
CPU 需求(核数)和 内存需求(MiB) :你可以为容器定义最小的
资源限制 。
默认情况下,Pod 没有 CPU 和内存限制。运行命令 和运行命令参数 :默认情况下,你的容器会运行 Docker 镜像的默认
入口命令 。
你可以使用 command 选项覆盖默认值。以特权模式运行 :这个设置决定了在
特权容器
中运行的进程是否像主机中使用 root 运行的进程一样。
特权容器可以使用诸如操纵网络堆栈和访问设备的功能。环境变量 :Kubernetes 通过
环境变量
暴露 Service。你可以构建环境变量,或者将环境变量的值作为参数传递给你的命令。
它们可以被应用用于查找 Service。值可以通过 $(VAR_NAME) 语法关联其他变量。上传 YAML 或者 JSON 文件 Kubernetes 支持声明式配置。所有的配置都存储在遵循 Kubernetes
API 规范的 YAML 或者 JSON 配置文件中。
作为一种替代在部署向导中指定应用详情的方式,你可以在 YAML 或者 JSON 文件中定义应用,并且使用 Dashboard 上传文件:
使用 Dashboard 以下各节描述了 Kubernetes Dashboard UI 视图;包括它们提供的内容,以及怎么使用它们。
导航 当在集群中定义 Kubernetes 对象时,Dashboard 会在初始视图中显示它们。
默认情况下只会显示 默认 名字空间中的对象,可以通过更改导航栏菜单中的名字空间筛选器进行改变。
Dashboard 展示大部分 Kubernetes 对象,并将它们分组放在几个菜单类别中。
管理概述 集群和名字空间管理的视图, Dashboard 会列出节点、名字空间和持久卷,并且有它们的详细视图。
节点列表视图包含从所有节点聚合的 CPU 和内存使用的度量值。
详细信息视图显示了一个节点的度量值,它的规格、状态、分配的资源、事件和这个节点上运行的 Pod。
负载 显示选中的名字空间中所有运行的应用。
视图按照负载类型(如 Deployment、ReplicaSet、StatefulSet 等)罗列应用,并且每种负载都可以单独查看。
列表总结了关于负载的可执行信息,比如一个 ReplicaSet 的准备状态的 Pod 数量,或者目前一个 Pod 的内存使用量。
工作负载的详情视图展示了对象的状态、详细信息和相互关系。
例如,ReplicaSet 所控制的 Pod,或者 Deployment 关联的 新 ReplicaSet 和 Pod 水平扩展控制器。
服务 展示允许暴露给外网服务和允许集群内部发现的 Kubernetes 资源。
因此,Service 和 Ingress 视图展示他们关联的 Pod、给集群连接使用的内部端点和给外部用户使用的外部端点。
存储 存储视图展示持久卷申领(PVC)资源,这些资源被应用程序用来存储数据。
ConfigMap 和 Secret 展示的所有 Kubernetes 资源是在集群中运行的应用程序的实时配置。
通过这个视图可以编辑和管理配置对象,并显示那些默认隐藏的 secret。
日志查看器 Pod 列表和详细信息页面可以链接到 Dashboard 内置的日志查看器。查看器可以钻取属于同一个 Pod 的不同容器的日志。
接下来 更多信息,参见 Kubernetes Dashboard 项目页面 .
4.9.2 - 访问集群 本文阐述多种与集群交互的方法。
使用 kubectl 完成集群的第一次访问 当你第一次访问 Kubernetes API 的时候,我们建议你使用 Kubernetes CLI,kubectl。
访问集群时,你需要知道集群的地址并且拥有访问的凭证。通常,这些在你通过
启动安装 安装集群时都是自动安装好的,或者其他人安装时
也应该提供了凭证和集群地址。
通过以下命令检查 kubectl 是否知道集群地址及凭证:
有许多 例子 介绍了如何使用 kubectl,
可以在 kubectl手册 中找到更完整的文档。
直接访问 REST API Kubectl 处理 apiserver 的定位和身份验证。
如果要使用 curl 或 wget 等 http 客户端或浏览器直接访问 REST API,可以通过
多种方式查找和验证:
以代理模式运行 kubectl。推荐此方式。 使用已存储的 apiserver 地址。 使用自签名的证书来验证 apiserver 的身份。杜绝 MITM 攻击。 对 apiserver 进行身份验证。 未来可能会实现智能化的客户端负载均衡和故障恢复。 直接向 http 客户端提供位置和凭据。可选的方案。 适用于代理可能引起混淆的某些客户端类型。 需要引入根证书到你的浏览器以防止 MITM 攻击。 使用 kubectl proxy 以下命令以反向代理的模式运行 kubectl。它处理 apiserver 的定位和验证。
像这样运行:
kubectl proxy --port= 8080 &
参阅 kubectl proxy
获取更多详细信息。
然后,你可以使用 curl、wget 或浏览器访问 API,如果是 IPv6 则用 [::1] 替换 localhost,
如下所示:
curl http://localhost:8080/api/
{
"kind" : "APIVersions" ,
"versions" : [
"v1"
],
"serverAddressByClientCIDRs" : [
{
"clientCIDR" : "0.0.0.0/0" ,
"serverAddress" : "10.0.1.149:443"
}
]
}
不使用 kubectl proxy 在 Kubernetes 1.3 或更高版本中,kubectl config view 不再显示 token。
使用 kubectl describe secret ... 来获取默认服务帐户的 token,如下所示:
grep/cut 方法实现:
APISERVER = $( kubectl config view | grep server | cut -f 2- -d ":" | tr -d " " )
TOKEN = $( kubectl describe secret $( kubectl get secrets | grep default | cut -f1 -d ' ' ) | grep -E '^token' | cut -f2 -d':' | tr -d ' ' )
curl $APISERVER /api --header "Authorization: Bearer $TOKEN " --insecure
{
"kind" : "APIVersions" ,
"versions" : [
"v1"
],
"serverAddressByClientCIDRs" : [
{
"clientCIDR" : "0.0.0.0/0" ,
"serverAddress" : "10.0.1.149:443"
}
]
}
jsonpath 方法实现:
APISERVER = $( kubectl config view --minify -o jsonpath = '{.clusters[0].cluster.server}' )
TOKEN = $( kubectl get secret $( kubectl get serviceaccount default -o jsonpath = '{.secrets[0].name}' ) -o jsonpath = '{.data.token}' | base64 --decode )
curl $APISERVER /api --header "Authorization: Bearer $TOKEN " --insecure
{
"kind" : "APIVersions" ,
"versions" : [
"v1"
],
"serverAddressByClientCIDRs" : [
{
"clientCIDR" : "0.0.0.0/0" ,
"serverAddress" : "10.0.1.149:443"
}
]
}
上面的例子使用了 --insecure 参数,这使得它很容易受到 MITM 攻击。
当 kubectl 访问集群时,它使用存储的根证书和客户端证书来访问服务器
(它们安装在 ~/.kube 目录中)。
由于集群证书通常是自签名的,因此可能需要特殊配置才能让你的 http 客户端使用根证书。
在一些集群中,apiserver 不需要身份验证;它可能只服务于 localhost,或者被防火墙保护,
这个没有一定的标准。
配置对 API 的访问
描述了集群管理员如何进行配置。此类方法可能与未来的高可用性支持相冲突。
以编程方式访问 API Kubernetes 官方提供对 Go 和 Python 的客户端库支持。
Go 客户端 想要获得这个库,请运行命令:go get k8s.io/client-go/<version number>/kubernetes。
参阅 https://github.com/kubernetes/client-go
来查看目前支持哪些版本。 基于这个 client-go 客户端库编写应用程序。
请注意,client-go 定义了自己的 API 对象,因此如果需要,请从 client-go 而不是从主存储库
导入 API 定义,例如,import "k8s.io/client-go/1.4/pkg/api/v1" 才是对的。 Go 客户端可以像 kubectl CLI 一样使用相同的
kubeconfig 文件
来定位和验证 apiserver。可参阅
示例 。
如果应用程序以 Pod 的形式部署在集群中,那么请参阅
下一章 。
Python 客户端 如果想要使用 Python 客户端 ,
请运行命令:pip install kubernetes。参阅
Python Client Library page
以获得更详细的安装参数。
Python 客户端可以像 kubectl CLI 一样使用相同的
kubeconfig 文件
来定位和验证 apiserver,可参阅
示例 。
其它语言 目前有多个客户端库
为其它语言提供访问 API 的方法。
参阅其它库的相关文档以获取他们是如何验证的。
从 Pod 中访问 API 当你从 Pod 中访问 API 时,定位和验证 apiserver 会有些许不同。
在 Pod 中定位 apiserver 的推荐方式是通过 kubernetes.default.svc
这个 DNS 名称,该名称将会解析为服务 IP,然后服务 IP 将会路由到 apiserver。
向 apiserver 进行身份验证的推荐方法是使用
服务帐户 凭据。
通过 kube-system,Pod 与服务帐户相关联,并且该服务帐户的凭证(token)
被放置在该 Pod 中每个容器的文件系统中,位于
/var/run/secrets/kubernetes.io/serviceaccount/token。
如果可用,则将证书放入每个容器的文件系统中的
/var/run/secrets/kubernetes.io/serviceaccount/ca.crt,
并且应该用于验证 apiserver 的服务证书。
最后,名字空间作用域的 API 操作所使用的 default 名字空间将被放置在
每个容器的 /var/run/secrets/kubernetes.io/serviceaccount/namespace
文件中。
在 Pod 中,建议连接 API 的方法是:
在 Pod 的边车容器中运行 kubectl proxy,或者以后台进程的形式运行。
这将把 Kubernetes API 代理到当前 Pod 的 localhost 接口,
所以 Pod 中的所有容器中的进程都能访问它。 使用 Go 客户端库,并使用 rest.InClusterConfig() 和
kubernetes.NewForConfig() 函数创建一个客户端。
他们处理 apiserver 的定位和身份验证。
示例 在每种情况下,Pod 的凭证都是为了与 apiserver 安全地通信。
访问集群中正在运行的服务 上一节介绍了如何连接 Kubernetes API 服务。本节介绍如何连接到 Kubernetes
集群上运行的其他服务。
在 Kubernetes 中,节点 、
pods 和
服务 都有自己的 IP。
在许多情况下,集群上的节点 IP、Pod IP 和某些服务 IP 将无法路由,
因此无法从集群外部的计算机(例如桌面计算机)访问它们。
连接的方法 有多种方式可以从集群外部连接节点、Pod 和服务:
通过公共 IP 访问服务。
类型为 NodePort 或 LoadBalancer 的服务,集群外部可以访问。
请参阅 服务 和
kubectl expose 文档。 取决于你的集群环境,该服务可能仅暴露给你的公司网络,或者也可能暴露给
整个互联网。
请考虑公开该服务是否安全。它是否进行自己的身份验证? 在服务后端放置 Pod。要从一组副本中访问一个特定的 Pod,例如进行调试,
请在 Pod 上设置一个唯一的标签,然后创建一个选择此标签的新服务。 在大多数情况下,应用程序开发人员不应该通过其 nodeIP 直接访问节点。 使用 proxy 动词访问服务、节点或者 Pod。在访问远程服务之前进行 apiserver 身份验证和授权。
如果服务不能够安全地暴露到互联网,或者服务不能获得节点 IP 端口的
访问权限,或者是为了调试,那么请使用此选项。 代理可能会给一些 web 应用带来问题。 只适用于 HTTP/HTTPS。 更多详细信息在这里 。 从集群中的节点或者 Pod 中访问。
运行一个 Pod,然后使用 kubectl exec
来连接 Pod 里的 Shell。
然后从 Shell 中连接其它的节点、Pod 和服务。 有些集群可能允许你通过 SSH 连接到节点,从那你可能可以访问集群的服务。
这是一个非正式的方式,可能可以运行在个别的集群上。
浏览器和其它一些工具可能没有被安装。集群的 DNS 可能无法使用。 发现内建服务 通常来说,集群中会有 kube-system 创建的一些运行的服务。
通过 kubectl cluster-info 命令获得这些服务列表:
Kubernetes master is running at https://104.197.5.247
elasticsearch-logging is running at https://104.197.5.247/api/v1/namespaces/kube-system/services/elasticsearch-logging/proxy
kibana-logging is running at https://104.197.5.247/api/v1/namespaces/kube-system/services/kibana-logging/proxy
kube-dns is running at https://104.197.5.247/api/v1/namespaces/kube-system/services/kube-dns/proxy
grafana is running at https://104.197.5.247/api/v1/namespaces/kube-system/services/monitoring-grafana/proxy
heapster is running at https://104.197.5.247/api/v1/namespaces/kube-system/services/monitoring-heapster/proxy
这展示了访问每个服务的 proxy-verb URL。
例如,如果集群启动了集群级别的日志(使用 Elasticsearch),并且传递合适的凭证,
那么可以通过
https://104.197.5.247/api/v1/namespaces/kube-system/services/elasticsearch-logging/proxy/
进行访问。日志也能通过 kubectl 代理获取,例如:
http://localhost:8080/api/v1/namespaces/kube-system/services/elasticsearch-logging/proxy/。
(参阅使用 Kubernetes API 访问集群
了解如何传递凭据,或者使用 kubectl proxy)
手动构建 apiserver 代理 URL 如上所述,你可以使用 kubectl cluster-info 命令来获得服务的代理 URL。
要创建包含服务端点、后缀和参数的代理 URL,只需添加到服务的代理 URL:
http://kubernetes_master_address/api/v1/namespaces/namespace_name/services/service_name[:port_name]/proxy
如果尚未为端口指定名称,则不必在 URL 中指定 port_name 。
默认情况下,API server 使用 HTTP 代理你的服务。
要使用 HTTPS,请在服务名称前加上 https::
http://kubernetes_master_address/api/v1/namespaces/namespace_name/services/https:service_name:[port_name]/proxy
URL 名称段支持的格式为:
<service_name> - 使用 http 代理到默认或未命名的端口<service_name>:<port_name> - 使用 http 代理到指定的端口https:<service_name>: - 使用 https 代理到默认或未命名的端口(注意后面的冒号)https:<service_name>:<port_name> - 使用 https 代理到指定的端口示例 要访问 Elasticsearch 服务端点 _search?q=user:kimchy,你需要使用:
http://104.197.5.247/api/v1/namespaces/kube-system/services/elasticsearch-logging/proxy/_search?q=user:kimchy 要访问 Elasticsearch 集群健康信息 _cluster/health?pretty=true,你需要使用:
https://104.197.5.247/api/v1/namespaces/kube-system/services/elasticsearch-logging/proxy/_cluster/health?pretty=true {
"cluster_name" : "kubernetes_logging" ,
"status" : "yellow" ,
"timed_out" : false ,
"number_of_nodes" : 1 ,
"number_of_data_nodes" : 1 ,
"active_primary_shards" : 5 ,
"active_shards" : 5 ,
"relocating_shards" : 0 ,
"initializing_shards" : 0 ,
"unassigned_shards" : 5
}
使用 web 浏览器访问运行在集群上的服务 你可以在浏览器地址栏中输入 apiserver 代理 URL。但是:
Web 浏览器通常不能传递令牌,因此你可能需要使用基本(密码)身份验证。
Apiserver 可以配置为接受基本身份验证,但你的集群可能未进行配置。 某些 Web 应用程序可能无法运行,尤其是那些使用客户端 javascript
以不知道代理路径前缀的方式构建 URL 的应用程序。 请求重定向 重定向功能已弃用并被删除。请改用代理(见下文)。
多种代理 使用 Kubernetes 时可能会遇到几种不同的代理:
kubectl 代理 :
在用户的桌面或 Pod 中运行 代理从本地主机地址到 Kubernetes apiserver 客户端到代理将使用 HTTP 代理到 apiserver 使用 HTTPS 定位 apiserver 添加身份验证头部 apiserver 代理 :
内置于 apiserver 中 将集群外部的用户连接到集群 IP,否则这些 IP 可能无法访问 运行在 apiserver 进程中 客户端代理使用 HTTPS(也可配置为 http) 代理将根据可用的信息决定使用 HTTP 或者 HTTPS 代理到目标 可用于访问节点、Pod 或服务 在访问服务时进行负载平衡 kube proxy :
运行在每个节点上 代理 UDP 和 TCP 不能代理 HTTP 提供负载均衡 只能用来访问服务 位于 apiserver 之前的 Proxy/Load-balancer:
存在和实现因集群而异(例如 nginx) 位于所有客户和一个或多个 apiserver 之间 如果有多个 apiserver,则充当负载均衡器 外部服务上的云负载均衡器:
由一些云提供商提供(例如 AWS ELB,Google Cloud Load Balancer) 当 Kubernetes 服务类型为 LoadBalancer 时自动创建 只使用 UDP/TCP 具体实现因云提供商而异。 除了前两种类型之外,Kubernetes 用户通常不需要担心任何其他问题。
集群管理员通常会确保后者的正确配置。
4.9.3 - 使用端口转发来访问集群中的应用 本文展示如何使用 kubectl port-forward 连接到在 Kubernetes 集群中
运行的 Redis 服务。这种类型的连接对数据库调试很有用。
准备开始 创建 Redis deployment 和服务 创建一个 Redis deployment:
kubectl apply -f https://k8s.io/examples/application/guestbook/redis-master-deployment.yaml
查看输出是否成功,以验证是否成功创建 deployment:
deployment.apps/redis-master created
查看 pod 状态,检查其是否准备就绪:
输出显示创建的 pod:
NAME READY STATUS RESTARTS AGE
redis-master-765d459796-258hz 1/1 Running 0 50s
查看 deployment 状态:
输出显示创建的 deployment:
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
redis-master 1 1 1 1 55s
查看 replicaset 状态:
输出显示创建的 replicaset:
NAME DESIRED CURRENT READY AGE
redis-master-765d459796 1 1 1 1m
创建一个 Redis 服务:
kubectl apply -f https://k8s.io/examples/application/guestbook/redis-master-service.yaml
查看输出是否成功,以验证是否成功创建 service:
service/redis-master created
检查 service 是否创建:
kubectl get svc | grep redis
输出显示创建的 service:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
redis-master ClusterIP 10.0.0.213 <none> 6379/TCP 27s
验证 Redis 服务是否运行在 pod 中并且监听 6379 端口:
kubectl get pods redis-master-765d459796-258hz \
--template= '{{(index (index .spec.containers 0).ports 0).containerPort}}{{"\n"}}'
输出应该显示端口:
6379
转发一个本地端口到 pod 端口 从 Kubernetes v1.10 开始,kubectl port-forward 允许使用资源名称
(例如 pod 名称)来选择匹配的 pod 来进行端口转发。
kubectl port-forward redis-master-765d459796-258hz 7000:6379
这相当于
kubectl port-forward pods/redis-master-765d459796-258hz 7000:6379
或者
kubectl port-forward deployment/redis-master 7000:6379
或者
kubectl port-forward rs/redis-master 7000:6379
或者
kubectl port-forward svc/redis-master 7000:redis
以上所有命令都应该有效。输出应该类似于:
Forwarding from 127.0.0.1:7000 -> 6379
Forwarding from [::1]:7000 -> 6379
说明: kubectl port-forward 不会返回。你需要打开另一个终端来继续这个练习。
启动 Redis 命令行接口:
在 Redis 命令行提示符下,输入 ping 命令:
ping
成功的 ping 请求应该返回:
PONG
(可选操作)让 kubectl 来选择本地端口 如果你不需要指定特定的本地端口,你可以让 kubectl 来选择和分配本地端口,
以便你不需要管理本地端口冲突。该命令使用稍微不同的语法:
kubectl port-forward deployment/redis-master :6379
kubectl 工具会找到一个未被使用的本地端口号(避免使用低段位的端口号,因为他们可能会被其他应用程序使用)。输出应该类似于:
Forwarding from 127.0.0.1:62162 -> 6379
Forwarding from [::1]:62162 -> 6379
讨论 与本地 7000 端口建立的连接将转发到运行 Redis 服务器的 pod 的 6379 端口。
通过此连接,您可以使用本地工作站来调试在 pod 中运行的数据库。
警告: 由于已知的限制,目前的端口转发仅适用于 TCP 协议。
在
issue 47862
中正在跟踪对 UDP 协议的支持。
接下来 进一步了解 kubectl port-forward 。
4.9.4 - 使用服务来访问集群中的应用 本文展示如何创建一个 Kubernetes 服务对象,能让外部客户端访问在集群中运行的应用。
该服务为一个应用的两个运行实例提供负载均衡。
准备开始
你必须拥有一个 Kubernetes 的集群,同时你的 Kubernetes 集群必须带有 kubectl 命令行工具。
如果你还没有集群,你可以通过 Minikube 构建一
个你自己的集群,或者你可以使用下面任意一个 Kubernetes 工具构建:
要获知版本信息,请输入
kubectl version.
教程目标 运行 Hello World 应用的两个实例。 创建一个服务对象来暴露 node port。 使用服务对象来访问正在运行的应用。 为运行在两个 pod 中的应用创建一个服务 这是应用程序部署的配置文件:
apiVersion : apps/v1
kind : Deployment
metadata :
name : hello-world
spec :
selector :
matchLabels :
run : load-balancer-example
replicas : 2
template :
metadata :
labels :
run : load-balancer-example
spec :
containers :
- name : hello-world
image : gcr.io/google-samples/node-hello:1.0
ports :
- containerPort : 8080
protocol : TCP
在你的集群中运行一个 Hello World 应用:
使用上面的文件创建应用程序 Deployment:
kubectl apply -f https://k8s.io/examples/service/access/hello-application.yaml
上面的命令创建一个 Deployment 对象
和一个关联的 ReplicaSet 对象。
这个 ReplicaSet 有两个 Pod ,
每个 Pod 都运行着 Hello World 应用。
展示 Deployment 的信息:
kubectl get deployments hello-world
kubectl describe deployments hello-world
展示你的 ReplicaSet 对象信息:
kubectl get replicasets
kubectl describe replicasets
创建一个服务对象来暴露 Deployment:
kubectl expose deployment hello-world --type= NodePort --name= example-service
展示 Service 信息:
kubectl describe services example-service
输出类似于:
Name: example-service
Namespace: default
Labels: run = load-balancer-example
Annotations: <none>
Selector: run = load-balancer-example
Type: NodePort
IP: 10.32.0.16
Port: <unset> 8080/TCP
TargetPort: 8080/TCP
NodePort: <unset> 31496/TCP
Endpoints: 10.200.1.4:8080,10.200.2.5:8080
Session Affinity: None
Events: <none>
注意服务中的 NodePort 值。例如在上面的输出中,NodePort 是 31496。
列出运行 Hello World 应用的 Pod:
kubectl get pods --selector= "run=load-balancer-example" --output= wide
输出类似于:
NAME READY STATUS ... IP NODE
hello-world-2895499144-bsbk5 1/1 Running ... 10.200.1.4 worker1
hello-world-2895499144-m1pwt 1/1 Running ... 10.200.2.5 worker2
获取运行 Hello World 的 pod 的其中一个节点的公共 IP 地址。如何获得此地址取决于你设置集群的方式。
例如,如果你使用的是 Minikube,则可以通过运行 kubectl cluster-info 来查看节点地址。
如果你使用的是 Google Compute Engine 实例,则可以使用 gcloud compute instances list 命令查看节点的公共地址。
在你选择的节点上,创建一个防火墙规则以开放节点端口上的 TCP 流量。
例如,如果你的服务的 NodePort 值为 31568,请创建一个防火墙规则以允许 31568 端口上的 TCP 流量。
不同的云提供商提供了不同方法来配置防火墙规则。
使用节点地址和 node port 来访问 Hello World 应用:
curl http://<public-node-ip>:<node-port>
这里的 <public-node-ip> 是你节点的公共 IP 地址,<node-port> 是你服务的 NodePort 值。
对于请求成功的响应是一个 hello 消息:
使用服务配置文件 作为 kubectl expose 的替代方法,你可以使用
服务配置文件 来创建服务。
清理现场 想要删除服务,输入以下命令:
kubectl delete services example-service
想要删除运行 Hello World 应用的 Deployment、ReplicaSet 和 Pod,输入以下命令:
kubectl delete deployment hello-world
接下来 4.9.5 - 使用 Service 把前端连接到后端 本任务会描述如何创建前端(Frontend)微服务和后端(Backend)微服务。后端微服务是一个 hello 欢迎程序。
前端通过 nginx 和一个 Kubernetes 服务
暴露后端所提供的服务。
教程目标 使用部署对象(Deployment object)创建并运行一个 hello 后端微服务 使用一个 Service 对象将请求流量发送到后端微服务的多个副本 同样使用一个 Deployment 对象创建并运行一个 nginx 前端微服务 配置前端微服务将请求流量发送到后端微服务 使用 type=LoadBalancer 的 Service 对象将全段微服务暴露到集群外部 准备开始
你必须拥有一个 Kubernetes 的集群,同时你的 Kubernetes 集群必须带有 kubectl 命令行工具。
如果你还没有集群,你可以通过 Minikube 构建一
个你自己的集群,或者你可以使用下面任意一个 Kubernetes 工具构建:
要获知版本信息,请输入
kubectl version.
本任务使用外部负载均衡服务 ,
所以需要对应的可支持此功能的环境。如果你的环境不能支持,你可以使用
NodePort
类型的服务代替。
使用部署对象(Deployment)创建后端 后端是一个简单的 hello 欢迎微服务应用。这是后端应用的 Deployment 配置文件:
---
apiVersion : apps/v1
kind : Deployment
metadata :
name : backend
spec :
selector :
matchLabels :
app : hello
tier : backend
track : stable
replicas : 3
template :
metadata :
labels :
app : hello
tier : backend
track : stable
spec :
containers :
- name : hello
image : "gcr.io/google-samples/hello-go-gke:1.0"
ports :
- name : http
containerPort : 80
... 创建后端 Deployment:
kubectl apply -f https://k8s.io/examples/service/access/backend-deployment.yaml
查看后端的 Deployment 信息:
kubectl describe deployment hello
输出类似于:
Name: backend
Namespace: default
CreationTimestamp: Mon, 24 Oct 2016 14:21:02 -0700
Labels: app=hello
tier=backend
track=stable
Annotations: deployment.kubernetes.io/revision=1
Selector: app=hello,tier=backend,track=stable
Replicas: 3 desired | 3 updated | 3 total | 3 available | 0 unavailable
StrategyType: RollingUpdate
MinReadySeconds: 0
RollingUpdateStrategy: 1 max unavailable, 1 max surge
Pod Template:
Labels: app=hello
tier=backend
track=stable
Containers:
hello:
Image: "gcr.io/google-samples/hello-go-gke:1.0"
Port: 80/TCP
Environment: <none>
Mounts: <none>
Volumes: <none>
Conditions:
Type Status Reason
---- ------ ------
Available True MinimumReplicasAvailable
Progressing True NewReplicaSetAvailable
OldReplicaSets: <none>
NewReplicaSet: hello-3621623197 (3/3 replicas created)
Events:
...
创建 hello Service 对象 将请求从前端发送到到后端的关键是后端 Service。Service 创建一个固定 IP 和 DNS 解析名入口,
使得后端微服务总是可达。Service 使用
选择算符
来寻找目标 Pod。
首先,浏览 Service 的配置文件:
---
apiVersion : v1
kind : Service
metadata :
name : hello
spec :
selector :
app : hello
tier : backend
ports :
- protocol : TCP
port : 80
targetPort : http
... 配置文件中,你可以看到名为 hello 的 Service 将流量路由到包含 app: hello
和 tier: backend 标签的 Pod。
创建后端 Service:
kubectl apply -f https://k8s.io/examples/service/access/backend-service.yaml
此时,你已经有了一个运行着 hello 应用的三个副本的 backend Deployment,你也有了
一个 Service 用于路由网络流量。不过,这个服务在集群外部无法访问也无法解析。
创建前端应用 现在你已经有了运行中的后端应用,你可以创建一个可在集群外部访问的前端,并通过代理
前端的请求连接到后端。
前端使用被赋予后端 Service 的 DNS 名称将请求发送到后端工作 Pods。这一 DNS
名称为 hello,也就是 examples/service/access/backend-service.yaml 配置
文件中 name 字段的取值。
前端 Deployment 中的 Pods 运行一个 nginx 镜像,这个已经配置好的镜像会将请求转发
给后端的 hello Service。下面是 nginx 的配置文件:
# The identifier Backend is internal to nginx, and used to name this specific upstream
upstream Backend {
# hello is the internal DNS name used by the backend Service inside Kubernetes
server hello;
}
server {
listen 80;
location / {
# The following statement will proxy traffic to the upstream named Backend
proxy_pass http://Backend;
}
}
与后端类似,前端用包含一个 Deployment 和一个 Service。后端与前端服务之间的一个
重要区别是前端 Service 的配置文件包含了 type: LoadBalancer,也就是说,Service
会使用你的云服务商的默认负载均衡设备,从而实现从集群外访问的目的。
---
apiVersion : v1
kind : Service
metadata :
name : frontend
spec :
selector :
app : hello
tier : frontend
ports :
- protocol : "TCP"
port : 80
targetPort : 80
type : LoadBalancer
... ---
apiVersion : apps/v1
kind : Deployment
metadata :
name : frontend
spec :
selector :
matchLabels :
app : hello
tier : frontend
track : stable
replicas : 1
template :
metadata :
labels :
app : hello
tier : frontend
track : stable
spec :
containers :
- name : nginx
image : "gcr.io/google-samples/hello-frontend:1.0"
lifecycle :
preStop :
exec :
command : ["/usr/sbin/nginx" ,"-s" ,"quit" ]
... 创建前端 Deployment 和 Service:
kubectl apply -f https://k8s.io/examples/service/access/frontend-deployment.yaml
kubectl apply -f https://k8s.io/examples/service/access/frontend-service.yaml
通过输出确认两个资源都已经被创建:
deployment.apps/frontend created
service/frontend created
说明: 这个 nginx 配置文件是被打包在
容器镜像 里的。
更好的方法是使用
ConfigMap ,
这样的话你可以更轻易地更改配置。
与前端 Service 交互 一旦你创建了 LoadBalancer 类型的 Service,你可以使用这条命令查看外部 IP:
kubectl get service frontend
外部 IP 字段的生成可能需要一些时间。如果是这种情况,外部 IP 会显示为 <pending>。
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
frontend 10.51.252.116 <pending> 80/TCP 10s
当外部 IP 地址被分配可用时,配置会更新,在 EXTERNAL-IP 头部下显示新的 IP:
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
frontend 10.51.252.116 XXX.XXX.XXX.XXX 80/TCP 1m
这一新的 IP 地址就可以用来从集群外与 frontend 服务交互了。
通过前端发送流量 前端和后端已经完成连接了。你可以使用 curl 命令通过你的前端 Service 的外部
IP 访问服务端点。
curl http://${ EXTERNAL_IP } # 将 EXTERNAL_P 替换为你之前看到的外部 IP
输出显示后端生成的消息:
清理现场 要删除服务,输入下面的命令:
kubectl delete services frontend backend
要删除在前端和后端应用中运行的 Deployment、ReplicaSet 和 Pod,输入下面的命令:
kubectl delete deployment frontend backend
接下来 4.9.6 - 创建外部负载均衡器 本文展示如何创建一个外部负载均衡器。
说明: 此功能仅适用于支持外部负载均衡器的云提供商或环境。
创建服务时,你可以选择自动创建云网络负载均衡器。这提供了一个外部可访问的 IP 地址,
可将流量分配到集群节点上的正确端口上
( 假设集群在支持的环境中运行,并配置了正确的云负载平衡器提供商包 )。
有关如何配置和使用 Ingress 资源为服务提供外部可访问的 URL、负载均衡流量、终止 SSL 等功能,
请查看 Ingress 文档。
准备开始 配置文件 要创建外部负载均衡器,请将以下内容添加到
服务配置文件 :
你的配置文件可能会如下所示:
apiVersion : v1
kind : Service
metadata :
name : example-service
spec :
selector :
app : example
ports :
- port : 8765
targetPort : 9376
type : LoadBalancer
使用 kubectl 你也可以使用 kubectl expose 命令及其 --type=LoadBalancer 参数创建服务:
kubectl expose rc example --port= 8765 --target-port= 9376 \
--name= example-service --type= LoadBalancer
此命令通过使用与引用资源(在上面的示例的情况下,名为 example 的 replication controller)相同的选择器来创建一个新的服务。
更多信息(包括更多的可选参数),请参阅
kubectl expose 指南 。
找到你的 IP 地址 你可以通过 kubectl 获取服务信息,找到为你的服务创建的 IP 地址:
kubectl describe services example-service
这将获得如下输出:
Name: example-service
Namespace: default
Labels: <none>
Annotations: <none>
Selector: app = example
Type: LoadBalancer
IP: 10.67.252.103
LoadBalancer Ingress: 192.0.2.89
Port: <unnamed> 80/TCP
NodePort: <unnamed> 32445/TCP
Endpoints: 10.64.0.4:80,10.64.1.5:80,10.64.2.4:80
Session Affinity: None
Events: <none>
IP 地址列在 LoadBalancer Ingress 旁边。
说明: 如果你在 Minikube 上运行服务,你可以通过以下命令找到分配的 IP 地址和端口:
minikube service example-service --url
保留客户端源 IP 由于此功能的实现,目标容器中看到的源 IP 将 不是客户端的原始源 IP 。
要启用保留客户端 IP,可以在服务的 spec 中配置以下字段(支持 GCE/Google Kubernetes Engine 环境):
service.spec.externalTrafficPolicy - 表示此服务是否希望将外部流量路由到节点本地或集群范围的端点。
有两个可用选项:Cluster(默认)和 Local。
Cluster 隐藏了客户端源 IP,可能导致第二跳到另一个节点,但具有良好的整体负载分布。
Local 保留客户端源 IP 并避免 LoadBalancer 和 NodePort 类型服务的第二跳,
但存在潜在的不均衡流量传播风险。service.spec.healthCheckNodePort - 指定服务的 healthcheck nodePort(数字端口号)。
如果未指定 healthCheckNodePort,服务控制器从集群的 NodePort 范围内分配一个端口。
你可以通过设置 API 服务器的命令行选项 --service-node-port-range 来配置上述范围。
它将会使用用户指定的 healthCheckNodePort 值(如果被客户端指定)。
仅当 type 设置为 LoadBalancer 并且 externalTrafficPolicy 设置为 Local 时才生效。可以通过在服务的配置文件中将 externalTrafficPolicy 设置为 Local 来激活此功能。
apiVersion : v1
kind : Service
metadata :
name : example-service
spec :
selector :
app : example
ports :
- port : 8765
targetPort : 9376
externalTrafficPolicy : Local
type : LoadBalancer
回收负载均衡器 在通常情况下,应在删除 LoadBalancer 类型服务后立即清除云提供商中的相关负载均衡器资源。
但是,众所周知,在删除关联的服务后,云资源被孤立的情况很多。
引入了针对服务负载均衡器的终结器保护,以防止这种情况发生。
通过使用终结器,在删除相关的负载均衡器资源之前,也不会删除服务资源。
具体来说,如果服务具有 type LoadBalancer,则服务控制器将附加一个名为
service.kubernetes.io/load-balancer-cleanup 的终结器。
仅在清除负载均衡器资源后才能删除终结器。
即使在诸如服务控制器崩溃之类的极端情况下,这也可以防止负载均衡器资源悬空。
外部负载均衡器提供商 请务必注意,此功能的数据路径由 Kubernetes 集群外部的负载均衡器提供。
当服务 type 设置为 LoadBalancer 时,Kubernetes 向集群中的 Pod 提供的功能等同于
type 等于 ClusterIP,并通过使用 Kubernetes pod 的条目对负载均衡器(从外部到 Kubernetes)
进行编程来扩展它。
Kubernetes 服务控制器自动创建外部负载均衡器、健康检查(如果需要)、防火墙规则(如果需要),
并获取云提供商分配的外部 IP 并将其填充到服务对象中。
保留源 IP 时的注意事项和限制 GCE/AWS 负载均衡器不为其目标池提供权重。
对于旧的 LB kube-proxy 规则来说,这不是一个问题,它可以在所有端点之间正确平衡。
使用新功能,外部流量不会在 pod 之间平均负载,而是在节点级别平均负载
(因为 GCE/AWS 和其他外部 LB 实现无法指定每个节点的权重,
因此它们的平衡跨所有目标节点,并忽略每个节点上的 Pod 数量)。
但是,我们可以声明,对于 NumServicePods << NumNodes 或 NumServicePods >> NumNodes 时,
即使没有权重,也会看到接近相等的分布。
一旦外部负载平衡器提供权重,就可以将此功能添加到 LB 编程路径中。
未来工作:1.4 版本不提供权重支持,但可能会在将来版本中添加
内部 Pod 到 Pod 的流量应该与 ClusterIP 服务类似,所有 Pod 的概率相同。
4.9.7 - 列出集群中所有运行容器的镜像 本文展示如何使用 kubectl 来列出集群中所有运行 Pod 的容器的镜像
准备开始
你必须拥有一个 Kubernetes 的集群,同时你的 Kubernetes 集群必须带有 kubectl 命令行工具。
如果你还没有集群,你可以通过 Minikube 构建一
个你自己的集群,或者你可以使用下面任意一个 Kubernetes 工具构建:
要获知版本信息,请输入
kubectl version.
在本练习中,你将使用 kubectl 来获取集群中运行的所有 Pod,并格式化输出来提取每个 Pod 中的容器列表。
列出所有命名空间下的所有容器 使用 kubectl get pods --all-namespaces 获取所有命名空间下的所有 Pod 使用 -o jsonpath={..image} 来格式化输出,以仅包含容器镜像名称。
这将以递归方式从返回的 json 中解析出 image 字段。 使用标准化工具来格式化输出:tr, sort, uniq使用 tr 以用换行符替换空格 使用 sort 来对结果进行排序 使用 uniq 来聚合镜像计数 kubectl get pods --all-namespaces -o jsonpath = "{..image}" |\
tr -s '[[:space:]]' '\n' |\
sort |\
uniq -c
上面的命令将递归获取所有返回项目的名为 image 的字段。
作为替代方案,可以使用 Pod 的镜像字段的绝对路径。这确保即使字段名称重复的情况下也能检索到正确的字段,例如,特定项目中的许多字段都称为 name:
kubectl get pods --all-namespaces -o jsonpath = "{.items[*].spec.containers[*].image}"
jsonpath 解释如下:
.items[*]: 对于每个返回的值.spec: 获取 spec.containers[*]: 对于每个容器.image: 获取镜像说明: 按名字获取单个 Pod 时,例如 kubectl get pod nginx,路径的 .items[*] 部分应该省略,
因为返回的是一个 Pod 而不是一个项目列表。
列出 Pod 中的容器 可以使用 range 操作进一步控制格式化,以单独操作每个元素。
kubectl get pods --all-namespaces -o= jsonpath = '{range .items[*]}{"\n"}{.metadata.name}{":\t"}{range .spec.containers[*]}{.image}{", "}{end}{end}' |\
sort
列出以标签过滤后的 Pod 的所有容器 要获取匹配特定标签的 Pod,请使用 -l 参数。以下匹配仅与标签 app=nginx 相符的 Pod。
kubectl get pods --all-namespaces -o= jsonpath = "{..image}" -l app = nginx
列出以命名空间过滤后的 Pod 的所有容器 要获取匹配特定命名空间的 Pod,请使用 namespace 参数。以下仅匹配 kube-system 命名空间下的 Pod。
kubectl get pods --namespace kube-system -o jsonpath = "{..image}"
使用 go-template 代替 jsonpath 来获取容器 作为 jsonpath 的替代,Kubectl 支持使用 go-templates 来格式化输出:
kubectl get pods --all-namespaces -o go-template --template= "{{range .items}}{{range .spec.containers}}{{.image}} {{end}}{{end}}"
接下来 参考 4.9.8 - 在 Minikube 环境中使用 NGINX Ingress 控制器配置 Ingress Ingress 是一种 API 对象,其中定义了一些规则使得集群中的
服务可以从集群外访问。
Ingress 控制器
负责满足 Ingress 中所设置的规则。
本节为你展示如何配置一个简单的 Ingress,根据 HTTP URI 将服务请求路由到
服务 web 或 web2。
准备开始
你必须拥有一个 Kubernetes 的集群,同时你的 Kubernetes 集群必须带有 kubectl 命令行工具。
如果你还没有集群,你可以通过 Minikube 构建一
个你自己的集群,或者你可以使用下面任意一个 Kubernetes 工具构建:
要获知版本信息,请输入
kubectl version.
创建一个 Minikube 集群 点击 Launch Terminal
Launch Terminal (可选操作)如果你在本地安装了 Minikube,运行下面的命令:
启用 Ingress 控制器 为了启用 NGINIX Ingress 控制器,可以运行下面的命令:
minikube addons enable ingress
检查验证 NGINX Ingress 控制器处于运行状态:
kubectl get pods -n kube-system
说明: 这一操作可能需要近一分钟时间。
输出:
NAME READY STATUS RESTARTS AGE
default-http-backend-59868b7dd6-xb8tq 1/1 Running 0 1m
kube-addon-manager-minikube 1/1 Running 0 3m
kube-dns-6dcb57bcc8-n4xd4 3/3 Running 0 2m
kubernetes-dashboard-5498ccf677-b8p5h 1/1 Running 0 2m
nginx-ingress-controller-5984b97644-rnkrg 1/1 Running 0 1m
storage-provisioner 1/1 Running 0 2m
部署一个 Hello World 应用 使用下面的命令创建一个 Deployment:
kubectl create deployment web --image= gcr.io/google-samples/hello-app:1.0
输出:
deployment.apps/web created
将 Deployment 暴露出来:
kubectl expose deployment web --type= NodePort --port= 8080
输出:
service/web exposed
验证 Service 已经创建,并且可能从节点端口访问:
输出:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT( S) AGE
web NodePort 10.104.133.249 <none> 8080:31637/TCP 12m
使用节点端口信息访问服务:
minikube service web --url
输出:
说明: 如果使用的是 Katacoda 环境,在终端面板顶端,请点击加号标志。
然后点击 Select port to view on Host 1 。
输入节点和端口号(这里是31637),之后点击 Display Port 。
输出:
Hello, world!
Version: 1.0.0
Hostname: web-55b8c6998d-8k564
你现在应该可以通过 Minikube 的 IP 地址和节点端口来访问示例应用了。
下一步是让自己能够通过 Ingress 资源来访问应用。
创建一个 Ingress 资源 下面是一个 Ingress 资源的配置文件,负责通过 hello-world.info 将服务请求
转发到你的服务。
根据下面的 YAML 创建文件 example-ingress.yaml:
apiVersion : networking.k8s.io/v1
kind : Ingress
metadata :
name : example-ingress
annotations :
nginx.ingress.kubernetes.io/rewrite-target : /$1
spec :
rules :
- host : hello-world.info
http :
paths :
- path : /
pathType : Prefix
backend :
service :
name : web
port :
number : 8080 通过运行下面的命令创建 Ingress 资源:
kubectl apply -f https://k8s.io/examples/service/networking/example-ingress.yaml
输出:
ingress.networking.k8s.io/example-ingress created
验证 IP 地址已被设置:
说明: 此操作可能需要几分钟时间。
NAME CLASS HOSTS ADDRESS PORTS AGE
example-ingress <none> hello-world.info 172.17.0.15 80 38s
在 /etc/hosts 文件的末尾添加以下内容:
说明: 如果你在本地运行 Minikube 环境,需要使用 minikube ip 获得外部 IP 地址。
Ingress 列表中显示的 IP 地址会是内部 IP 地址。
172.17.0.15 hello-world.info
此设置使得来自 hello-world.info 的请求被发送到 Minikube。
验证 Ingress 控制器能够转发请求流量:
输出:
Hello, world!
Version: 1.0.0
Hostname: web-55b8c6998d-8k564
说明: 如果你在使用本地 Minikube 环境,你可以从浏览器中访问 hello-world.info。
创建第二个 Deployment 使用下面的命令创建 v2 的 Deployment:
kubectl create deployment web2 --image= gcr.io/google-samples/hello-app:2.0
输出:
deployment.apps/web2 created
将 Deployment 暴露出来:
kubectl expose deployment web2 --port= 8080 --type= NodePort
输出:
service/web2 exposed
编辑 Ingress 编辑现有的 example-ingress.yaml,添加以下行:
- path : /v2
pathType : Prefix
backend :
service :
name : web2
port :
number : 8080
应用所作变更:
kubectl apply -f example-ingress.yaml
输出:
ingress.networking/example-ingress configured
测试你的 Ingress 访问 HelloWorld 应用的第一个版本:
输出:
Hello, world!
Version: 1.0.0
Hostname: web-55b8c6998d-8k564
访问 HelloWorld 应用的第二个版本:
输出:
Hello, world!
Version: 2.0.0
Hostname: web2-75cd47646f-t8cjk
说明: 如果你在本地运行 Minikube 环境,你可以使用浏览器来访问
hello-world.info 和 hello-world.info/v2。
接下来 4.9.9 - 为集群配置 DNS Kubernetes 提供 DNS 集群插件,大多数支持的环境默认情况下都会启用。
在 Kubernetes 1.11 及其以后版本中,推荐使用 CoreDNS,
kubeadm 默认会安装 CoreDNS。
要了解关于如何为 Kubernetes 集群配置 CoreDNS 的更多信息,参阅
定制 DNS 服务 。
关于如何利用 kube-dns 配置 kubernetes DNS 的演示例子,参阅
Kubernetes DNS 插件示例 。
4.9.10 - 同 Pod 内的容器使用共享卷通信 本文旨在说明如何让一个 Pod 内的两个容器使用一个卷(Volume)进行通信。
参阅如何让两个进程跨容器通过
共享进程名字空间 。
准备开始
你必须拥有一个 Kubernetes 的集群,同时你的 Kubernetes 集群必须带有 kubectl 命令行工具。
如果你还没有集群,你可以通过 Minikube 构建一
个你自己的集群,或者你可以使用下面任意一个 Kubernetes 工具构建:
要获知版本信息,请输入
kubectl version.
创建一个包含两个容器的 Pod 在这个练习中,你会创建一个包含两个容器的 Pod。两个容器共享一个卷用于他们之间的通信。
Pod 的配置文件如下:
apiVersion : v1
kind : Pod
metadata :
name : two-containers
spec :
restartPolicy : Never
volumes :
- name : shared-data
emptyDir : {}
containers :
- name : nginx-container
image : nginx
volumeMounts :
- name : shared-data
mountPath : /usr/share/nginx/html
- name : debian-container
image : debian
volumeMounts :
- name : shared-data
mountPath : /pod-data
command : ["/bin/sh" ]
args : ["-c" , "echo Hello from the debian container > /pod-data/index.html" ]
在配置文件中,你可以看到 Pod 有一个共享卷,名为 shared-data。
配置文件中的第一个容器运行了一个 nginx 服务器。共享卷的挂载路径是 /usr/share/nginx/html。
第二个容器是基于 debian 镜像的,有一个 /pod-data 的挂载路径。第二个容器运行了下面的命令然后终止。
echo Hello from the debian container > /pod-data/index.html
注意,第二个容器在 nginx 服务器的根目录下写了 index.html 文件。
创建一个包含两个容器的 Pod:
kubectl apply -f https://k8s.io/examples/pods/two-container-pod.yaml
查看 Pod 和容器的信息:
kubectl get pod two-containers --output= yaml
这是输出的一部分:
apiVersion : v1
kind : Pod
metadata :
...
name : two-containers
namespace : default
...
spec :
...
containerStatuses :
- containerID : docker://c1d8abd1 ...
image : debian
...
lastState :
terminated :
...
name : debian-container
...
- containerID : docker://96c1ff2c5bb ...
image : nginx
...
name : nginx-container
...
state :
running :
...
你可以看到 debian 容器已经被终止了,而 nginx 服务器依然在运行。
进入 nginx 容器的 shell:
kubectl exec -it two-containers -c nginx-container -- /bin/bash
在 shell 中,确认 nginx 还在运行。
root@two-containers:/# ps aux
输出类似于这样:
USER PID ... STAT START TIME COMMAND
root 1 ... Ss 21:12 0:00 nginx: master process nginx -g daemon off;
回忆一下,debian 容器在 nginx 的根目录下创建了 index.html 文件。
使用 curl 向 nginx 服务器发送一个 GET 请求:
root@two-containers:/# curl localhost
输出表示 nginx 提供了 debian 容器写的页面:
Hello from the debian container
讨论 Pod 能有多个容器的主要原因是为了支持辅助应用(helper applications),以协助主应用(primary application)。
辅助应用的典型例子是数据抽取,数据推送和代理。辅助应用和主应用经常需要相互通信。
就如这个练习所示,通信通常是通过共享文件系统完成的,或者,也通过回环网络接口 localhost 完成。
举个网络接口的例子,web 服务器带有一个协助程序用于拉取 Git 仓库的更新。
在本练习中的卷为 Pod 生命周期中的容器相互通信提供了一种方法。如果 Pod 被删除或者重建了,
任何共享卷中的数据都会丢失。
接下来 4.9.11 - 配置对多集群的访问 本文展示如何使用配置文件来配置对多个集群的访问。 在将集群、用户和上下文定义在一个或多个配置文件中之后,用户可以使用 kubectl config use-context 命令快速地在集群之间进行切换。
说明: 用于配置集群访问的文件有时被称为 kubeconfig 文件 。
这是一种引用配置文件的通用方式,并不意味着存在一个名为 kubeconfig 的文件。
准备开始 你必须拥有一个 Kubernetes 的集群,同时你的 Kubernetes 集群必须带有 kubectl 命令行工具。
如果你还没有集群,你可以通过 Minikube 构建一
个你自己的集群,或者你可以使用下面任意一个 Kubernetes 工具构建:
要检查 kubectl 是否安装,
执行 kubectl version --client 命令。
kubectl 的版本应该与集群的 API 服务器
使用同一次版本号 。
定义集群、用户和上下文 假设用户有两个集群,一个用于正式开发工作,一个用于其它临时用途(scratch)。
在 development 集群中,前端开发者在名为 frontend 的名字空间下工作,
存储开发者在名为 storage 的名字空间下工作。 在 scratch 集群中,
开发人员可能在默认名字空间下工作,也可能视情况创建附加的名字空间。
访问开发集群需要通过证书进行认证。
访问其它临时用途的集群需要通过用户名和密码进行认证。
创建名为 config-exercise 的目录。 在
config-exercise 目录中,创建名为 config-demo 的文件,其内容为:
apiVersion : v1
kind : Config
preferences : {}
clusters :
- cluster :
name : development
- cluster :
name : scratch
users :
- name : developer
- name : experimenter
contexts :
- context :
name : dev-frontend
- context :
name : dev-storage
- context :
name : exp-scratch
配置文件描述了集群、用户名和上下文。config-demo 文件中含有描述两个集群、
两个用户和三个上下文的框架。
进入 config-exercise 目录。输入以下命令,将群集详细信息添加到配置文件中:
kubectl config --kubeconfig= config-demo set-cluster development --server= https://1.2.3.4 --certificate-authority= fake-ca-file
kubectl config --kubeconfig= config-demo set-cluster scratch --server= https://5.6.7.8 --insecure-skip-tls-verify
将用户详细信息添加到配置文件中:
kubectl config --kubeconfig= config-demo set-credentials developer --client-certificate= fake-cert-file --client-key= fake-key-seefile
kubectl config --kubeconfig= config-demo set-credentials experimenter --username= exp --password= some-password
注意:
要删除用户,可以运行 kubectl --kubeconfig=config-demo config unset users.<name> 要删除集群,可以运行 kubectl --kubeconfig=config-demo config unset clusters.<name> 要删除上下文,可以运行 kubectl --kubeconfig=config-demo config unset contexts.<name> 将上下文详细信息添加到配置文件中:
kubectl config --kubeconfig= config-demo set-context dev-frontend --cluster= development --namespace= frontend --user= developer
kubectl config --kubeconfig= config-demo set-context dev-storage --cluster= development --namespace= storage --user= developer
kubectl config --kubeconfig= config-demo set-context exp-scratch --cluster= scratch --namespace= default --user= experimenter
打开 config-demo 文件查看添加的详细信息。 也可以使用 config view
命令进行查看:
kubectl config --kubeconfig= config-demo view
输出展示了两个集群、两个用户和三个上下文:
apiVersion : v1
clusters :
- cluster :
certificate-authority : fake-ca-file
server : https://1.2.3.4
name : development
- cluster :
insecure-skip-tls-verify : true
server : https://5.6.7.8
name : scratch
contexts :
- context :
cluster : development
namespace : frontend
user : developer
name : dev-frontend
- context :
cluster : development
namespace : storage
user : developer
name : dev-storage
- context :
cluster : scratch
namespace : default
user : experimenter
name : exp-scratch
current-context : ""
kind : Config
preferences : {}
users :
- name : developer
user :
client-certificate : fake-cert-file
client-key : fake-key-file
- name : experimenter
user :
password : some-password
username : exp
其中的 fake-ca-file、fake-cert-file 和 fake-key-file 是证书文件路径名的占位符。
你需要更改这些值,使之对应你的环境中证书文件的实际路径名。
有时你可能希望在这里使用 BASE64 编码的数据而不是一个个独立的证书文件。
如果是这样,你需要在键名上添加 -data 后缀。例如,
certificate-authority-data、client-certificate-data 和 client-key-data。
每个上下文包含三部分(集群、用户和名字空间),例如,
dev-frontend 上下文表明:使用 developer 用户的凭证来访问 development 集群的
frontend 名字空间。
设置当前上下文:
kubectl config --kubeconfig= config-demo use-context dev-frontend
现在当输入 kubectl 命令时,相应动作会应用于 dev-frontend 上下文中所列的集群和名字空间,
同时,命令会使用 dev-frontend 上下文中所列用户的凭证。
使用 --minify 参数,来查看与当前上下文相关联的配置信息。
kubectl config --kubeconfig= config-demo view --minify
输出结果展示了 dev-frontend 上下文相关的配置信息:
apiVersion : v1
clusters :
- cluster :
certificate-authority : fake-ca-file
server : https://1.2.3.4
name : development
contexts :
- context :
cluster : development
namespace : frontend
user : developer
name : dev-frontend
current-context : dev-frontend
kind : Config
preferences : {}
users :
- name : developer
user :
client-certificate : fake-cert-file
client-key : fake-key-file
现在假设用户希望在其它临时用途集群中工作一段时间。
将当前上下文更改为 exp-scratch:
kubectl config --kubeconfig= config-demo use-context exp-scratch
现在你发出的所有 kubectl 命令都将应用于 scratch 集群的默认名字空间。
同时,命令会使用 exp-scratch 上下文中所列用户的凭证。
查看更新后的当前上下文 exp-scratch 相关的配置:
kubectl config --kubeconfig= config-demo view --minify
最后,假设用户希望在 development 集群中的 storage 名字空间下工作一段时间。
将当前上下文更改为 dev-storage:
kubectl config --kubeconfig= config-demo use-context dev-storage
查看更新后的当前上下文 dev-storage 相关的配置:
kubectl config --kubeconfig= config-demo view --minify
创建第二个配置文件 在 config-exercise 目录中,创建名为 config-demo-2 的文件,其中包含以下内容:
apiVersion : v1
kind : Config
preferences : {}
contexts :
- context :
cluster : development
namespace : ramp
user : developer
name : dev-ramp-up
上述配置文件定义了一个新的上下文,名为 dev-ramp-up。
设置 KUBECONFIG 环境变量 查看是否有名为 KUBECONFIG 的环境变量。
如有,保存 KUBECONFIG 环境变量当前的值,以便稍后恢复。
例如:
Linux export KUBECONFIG_SAVED = $KUBECONFIG
Windows PowerShell $Env :KUBECONFIG_SAVED= $ENV :KUBECONFIG
KUBECONFIG 环境变量是配置文件路径的列表,该列表在 Linux 和 Mac 中以冒号分隔,
在 Windows 中以分号分隔。
如果有 KUBECONFIG 环境变量,请熟悉列表中的配置文件。
临时添加两条路径到 KUBECONFIG 环境变量中。 例如:
Linux export KUBECONFIG = $KUBECONFIG :config-demo:config-demo-2
Windows PowerShell $Env :KUBECONFIG=( "config-demo;config-demo-2" )
在 config-exercise 目录中输入以下命令:
输出展示了 KUBECONFIG 环境变量中所列举的所有文件合并后的信息。
特别地,注意合并信息中包含来自 config-demo-2 文件的 dev-ramp-up 上下文和来自
config-demo 文件的三个上下文:
contexts :
- context :
cluster : development
namespace : frontend
user : developer
name : dev-frontend
- context :
cluster : development
namespace : ramp
user : developer
name : dev-ramp-up
- context :
cluster : development
namespace : storage
user : developer
name : dev-storage
- context :
cluster : scratch
namespace : default
user : experimenter
name : exp-scratch
关于 kubeconfig 文件如何合并的更多信息,请参考
使用 kubeconfig 文件组织集群访问
探索 $HOME/.kube 目录 如果用户已经拥有一个集群,可以使用 kubectl 与集群进行交互,
那么很可能在 $HOME/.kube 目录下有一个名为 config 的文件。
进入 $HOME/.kube 目录,看看那里有什么文件。通常会有一个名为
config 的文件,目录中可能还有其他配置文件。请简单地熟悉这些文件的内容。
将 $HOME/.kube/config 追加到 KUBECONFIG 环境变量中 如果有 $HOME/.kube/config 文件,并且还未列在 KUBECONFIG 环境变量中,
那么现在将它追加到 KUBECONFIG 环境变量中。
例如:
Linux export KUBECONFIG = $KUBECONFIG :$HOME /.kube/config
Windows Powershell $Env :KUBECONFIG= " $Env :KUBECONFIG; $HOME \.kube\config"
在配置练习目录中输入以下命令,查看当前 KUBECONFIG 环境变量中列举的所有文件合并后的配置信息:
清理 将 KUBECONFIG 环境变量还原为原始值。 例如:
Linux export KUBECONFIG = $KUBECONFIG_SAVED
Windows PowerShell $Env :KUBECONFIG= $ENV :KUBECONFIG_SAVED
接下来 4.10 - 监控、日志和排错 设置监视和日志记录以对集群进行故障排除或调试容器化应用。
4.10.1 - 使用 crictl 对 Kubernetes 节点进行调试 FEATURE STATE: Kubernetes v1.11 [stable]
crictl 是 CRI 兼容的容器运行时命令行接口。
你可以使用它来检查和调试 Kubernetes 节点上的容器运行时和应用程序。
crictl 和它的源代码在
cri-tools 代码库。
准备开始 crictl 需要带有 CRI 运行时的 Linux 操作系统。
安装 crictl 你可以从 cri-tools 发布页面
下载一个压缩的 crictl 归档文件,用于几种不同的架构。
下载与你的 kubernetes 版本相对应的版本。
提取它并将其移动到系统路径上的某个位置,例如/usr/local/bin/。
一般用法 crictl 命令有几个子命令和运行时参数。
有关详细信息,请使用 crictl help 或 crictl <subcommand> help 获取帮助信息。
crictl 默认连接到 unix:///var/run/dockershim.sock。
对于其他的运行时,你可以用多种不同的方法设置端点:
通过设置参数 --runtime-endpoint 和 --image-endpoint 通过设置环境变量 CONTAINER_RUNTIME_ENDPOINT 和 IMAGE_SERVICE_ENDPOINT 通过在配置文件中设置端点 --config=/etc/crictl.yaml 你还可以在连接到服务器并启用或禁用调试时指定超时值,方法是在配置文件中指定
timeout 或 debug 值,或者使用 --timeout 和 --debug 命令行参数。
要查看或编辑当前配置,请查看或编辑 /etc/crictl.yaml 的内容。
runtime-endpoint: unix:///var/run/dockershim.sock
image-endpoint: unix:///var/run/dockershim.sock
timeout: 10
debug: true
crictl 命令示例 警告: 如果使用 crictl 在正在运行的 Kubernetes 集群上创建 Pod 沙盒或容器,
kubelet 最终将删除它们。
crictl 不是一个通用的工作流工具,而是一个对调试有用的工具。
打印 Pod 清单 打印所有 Pod 的清单:
POD ID CREATED STATE NAME NAMESPACE ATTEMPT
926f1b5a1d33a About a minute ago Ready sh-84d7dcf559-4r2gq default 0
4dccb216c4adb About a minute ago Ready nginx-65899c769f-wv2gp default 0
a86316e96fa89 17 hours ago Ready kube-proxy-gblk4 kube-system 0
919630b8f81f1 17 hours ago Ready nvidia-device-plugin-zgbbv kube-system 0
根据名称打印 Pod 清单:
crictl pods --name nginx-65899c769f-wv2gp
POD ID CREATED STATE NAME NAMESPACE ATTEMPT
4dccb216c4adb 2 minutes ago Ready nginx-65899c769f-wv2gp default 0
根据标签打印 Pod 清单:
crictl pods --label run = nginx
POD ID CREATED STATE NAME NAMESPACE ATTEMPT
4dccb216c4adb 2 minutes ago Ready nginx-65899c769f-wv2gp default 0
打印镜像清单 打印所有镜像清单:
IMAGE TAG IMAGE ID SIZE
busybox latest 8c811b4aec35f 1.15MB
k8s-gcrio.azureedge.net/hyperkube-amd64 v1.10.3 e179bbfe5d238 665MB
k8s-gcrio.azureedge.net/pause-amd64 3.1 da86e6ba6ca19 742kB
nginx latest cd5239a0906a6 109MB
根据仓库打印镜像清单:
IMAGE TAG IMAGE ID SIZE
nginx latest cd5239a0906a6 109MB
只打印镜像 ID:
sha256:8c811b4aec35f259572d0f79207bc0678df4c736eeec50bc9fec37ed936a472a
sha256:e179bbfe5d238de6069f3b03fccbecc3fb4f2019af741bfff1233c4d7b2970c5
sha256:da86e6ba6ca197bf6bc5e9d900febd906b133eaa4750e6bed647b0fbe50ed43e
sha256:cd5239a0906a6ccf0562354852fae04bc5b52d72a2aff9a871ddb6bd57553569
打印容器清单 打印所有容器清单:
CONTAINER ID IMAGE CREATED STATE NAME ATTEMPT
1f73f2d81bf98 busybox@sha256:141c253bc4c3fd0a201d32dc1f493bcf3fff003b6df416dea4f41046e0f37d47 7 minutes ago Running sh 1
9c5951df22c78 busybox@sha256:141c253bc4c3fd0a201d32dc1f493bcf3fff003b6df416dea4f41046e0f37d47 8 minutes ago Exited sh 0
87d3992f84f74 nginx@sha256:d0a8828cccb73397acb0073bf34f4d7d8aa315263f1e7806bf8c55d8ac139d5f 8 minutes ago Running nginx 0
1941fb4da154f k8s-gcrio.azureedge.net/hyperkube-amd64@sha256:00d814b1f7763f4ab5be80c58e98140dfc69df107f253d7fdd714b30a714260a 18 hours ago Running kube-proxy 0
打印正在运行的容器清单:
CONTAINER ID IMAGE CREATED STATE NAME ATTEMPT
1f73f2d81bf98 busybox@sha256:141c253bc4c3fd0a201d32dc1f493bcf3fff003b6df416dea4f41046e0f37d47 6 minutes ago Running sh 1
87d3992f84f74 nginx@sha256:d0a8828cccb73397acb0073bf34f4d7d8aa315263f1e7806bf8c55d8ac139d5f 7 minutes ago Running nginx 0
1941fb4da154f k8s-gcrio.azureedge.net/hyperkube-amd64@sha256:00d814b1f7763f4ab5be80c58e98140dfc69df107f253d7fdd714b30a714260a 17 hours ago Running kube-proxy 0
在正在运行的容器上执行命令 crictl exec -i -t 1f73f2d81bf98 ls
bin dev etc home proc root sys tmp usr var
获取容器日志 获取容器的所有日志:
crictl logs 87d3992f84f74
10.240.0.96 - - [06/Jun/2018:02:45:49 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.47.0" "-"
10.240.0.96 - - [06/Jun/2018:02:45:50 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.47.0" "-"
10.240.0.96 - - [06/Jun/2018:02:45:51 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.47.0" "-"
获取最近的 N 行日志:
crictl logs --tail= 1 87d3992f84f74
10.240.0.96 - - [06/Jun/2018:02:45:51 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.47.0" "-"
运行 Pod 沙盒 用 crictl 运行 Pod 沙盒对容器运行时排错很有帮助。
在运行的 Kubernetes 集群中,沙盒会随机地被 kubelet 停止和删除。
编写下面的 JSON 文件:
{
"metadata" : {
"name" : "nginx-sandbox" ,
"namespace" : "default" ,
"attempt" : 1 ,
"uid" : "hdishd83djaidwnduwk28bcsb"
},
"logDirectory" : "/tmp" ,
"linux" : {
}
}
使用 crictl runp 命令应用 JSON 文件并运行沙盒。
crictl runp pod-config.json
返回了沙盒的 ID。
创建容器 用 crictl 创建容器对容器运行时排错很有帮助。
在运行的 Kubernetes 集群中,沙盒会随机的被 kubelet 停止和删除。
拉取 busybox 镜像
crictl pull busybox
Image is up to date for busybox@sha256:141c253bc4c3fd0a201d32dc1f493bcf3fff003b6df416dea4f41046e0f37d47
创建 Pod 和容器的配置:
Pod 配置 :
{
"metadata": {
"name": "nginx-sandbox" ,
"namespace": "default" ,
"attempt": 1 ,
"uid": "hdishd83djaidwnduwk28bcsb"
},
"log_directory": "/tmp" ,
"linux": {
}
}
容器配置 :
{
"metadata": {
"name": "busybox"
},
"image" :{
"image": "busybox"
},
"command": [
"top"
],
"log_path" :"busybox.log" ,
"linux": {
}
}
创建容器,传递先前创建的 Pod 的 ID、容器配置文件和 Pod 配置文件。返回容器的 ID。
crictl create f84dd361f8dc51518ed291fbadd6db537b0496536c1d2d6c05ff943ce8c9a54f container-config.json pod-config.json
查询所有容器并确认新创建的容器状态为 Created。
CONTAINER ID IMAGE CREATED STATE NAME ATTEMPT
3e025dd50a72d busybox 32 seconds ago Created busybox 0
启动容器 要启动容器,要将容器 ID 传给 crictl start:
crictl start 3e025dd50a72d956c4f14881fbb5b1080c9275674e95fb67f965f6478a957d60
3e025dd50a72d956c4f14881fbb5b1080c9275674e95fb67f965f6478a957d60
确认容器的状态为 Running。
CONTAINER ID IMAGE CREATED STATE NAME ATTEMPT
3e025dd50a72d busybox About a minute ago Running busybox 0
更多信息请参考 kubernetes-sigs/cri-tools 。
Docker CLI 和 crictl 的映射 以下的映射表格只适用于 Docker CLI v1.40 和 crictl v1.19.0 版本。
请注意该表格并不详尽。例如,其中不包含 Docker CLI 的实验性命令。
说明: 尽管有些命令的输出缺少了一些数据列,CRICTL 的输出格式与 Docker CLI 是类似的。
如果你的脚本程序需要解析命令的输出,请确认检查该特定命令的输出。
mapping from docker cli to crictl - retrieve debugging information docker cli crictl 描述 不支持的功能 attachattach连接到一个运行中的容器 --detach-keys, --sig-proxyexecexec在运行中的容器里运行一个命令 --privileged, --user, --detach-keysimagesimages列举镜像 infoinfo显示系统级的信息 inspectinspect, inspecti返回容器、镜像或者任务的详细信息 logslogs获取容器的日志 --detailspsps列举容器 statsstats实时显示容器的资源使用统计信息 列:NET/BLOCK I/O, PIDs versionversion显示运行时(Docker、ContainerD、或者其他) 的版本信息
mapping from docker cli to crictl - perform changes docker cli crictl 描述 不支持的功能 createcreate创建一个新的容器 killstop (timeout=0)杀死一个或多个正在运行的容器 --signalpullpull从镜像仓库拉取镜像或者代码仓库 --all-tags, --disable-content-trustrmrm移除一个或多个容器 rmirmi移除一个或多个镜像 runrun在新容器里运行一个命令 startstart启动一个或多个停止的容器 --detach-keysstopstop停止一个或多个正运行的容器 updateupdate更新一个或多个容器的配置 CRI 不支持 --restart、--blkio-weight 以及一些其他的资源限制选项。
mapping from docker cli to crictl - supported only in crictl crictl 描述 imagefsinfo返回镜像的文件系统信息 inspectp显示一个或多个 Pod 的状态 port-forward转发本地端口到 Pod pods列举 Pod runp运行一个新的 Pod rmp移除一个或多个 Pod stopp停止一个或多个正运行的 Pod
4.10.2 - 使用 Stackdriver 生成日志 在阅读这篇文档之前,强烈建议你先熟悉一下 Kubernetes 日志概况
说明: 默认情况下,Stackdriver 日志机制仅收集容器的标准输出和标准错误流。
如果要收集你的应用程序写入一个文件(例如)的任何日志,请参见 Kubernetes 日志概述中的
sidecar 方式 部署 为了接收日志,你必须将 Stackdriver 日志代理部署到集群中的每个节点。
此代理是一个已配置的 fluentd,其配置存在一个 ConfigMap 中,且实例使用 Kubernetes 的 DaemonSet 进行管理。
ConfigMap 和 DaemonSet 的实际部署,取决你的集群设置。
部署到一个新的集群 Google Kubernetes Engine 对于部署在 Google Kubernetes Engine 上的集群,Stackdriver 是默认的日志解决方案。
Stackdriver 日志机制会默认部署到你的新集群上,除非你明确地不选择。
其他平台 为了将 Stackdriver 日志机制部署到你正在使用 kube-up.sh 创建的新 集群上,执行如下操作:
设置环境变量 KUBE_LOGGING_DESTINATION 为 gcp。 如果不是跑在 GCE 上 ,在 KUBE_NODE_LABELS 变量中包含 beta.kubernetes.io/fluentd-ds-ready=true。集群启动后,每个节点都应该运行 Stackdriver 日志代理。
DaemonSet 和 ConfigMap 作为附加组件进行配置。
如果你不是使用 kube-up.sh,可以考虑不使用预先配置的日志方案启动集群,然后部署 Stackdriver 日志代理到正在运行的集群。
警告: 除了 Google Kubernetes Engine,Stackdriver 日志守护进程在其他的平台有已知的问题。
请自行承担风险。
部署到一个已知集群 在每个节点上打标签(如果尚未存在)
Stackdriver 日志代理部署使用节点标签来确定应该将其分配到给哪些节点。
引入这些标签是为了区分 Kubernetes 1.6 或更高版本的节点。
如果集群是在配置了 Stackdriver 日志机制的情况下创建的,并且节点的版本为 1.5.X 或更低版本,则它将使用 fluentd 用作静态容器。
节点最多只能有一个 fluentd 实例,因此只能将标签打在未分配过 fluentd pod 的节点上。
你可以通过运行 kubectl describe 来确保你的节点被正确标记,如下所示:
kubectl describe node $NODE_NAME
输出应类似于如下内容:
Name: NODE_NAME
Role:
Labels: beta.kubernetes.io/fluentd-ds-ready=true
...
确保输出内容包含 beta.kubernetes.io/fluentd-ds-ready=true 标签。
如果不存在,则可以使用 kubectl label 命令添加,如下所示:
kubectl label node $NODE_NAME beta.kubernetes.io/fluentd-ds-ready=true
说明: 如果节点发生故障并且必须重新创建,则必须将标签重新打在重新创建了的节点。
为了让此操作更便捷,你可以在节点启动脚本中使用 Kubelet 的命令行参数给节点添加标签。
通过运行以下命令,部署一个带有日志代理配置的 ConfigMap:
kubectl apply -f https://k8s.io/examples/debug/fluentd-gcp-configmap.yaml
该命令在 default 命名空间中创建 ConfigMap。你可以在创建 ConfigMap 对象之前手动下载文件并进行更改。
通过运行以下命令,部署日志代理的 DaemonSet:
kubectl apply -f https://k8s.io/examples/debug/fluentd-gcp-ds.yaml
你也可以在使用前下载和编辑此文件。
验证日志代理部署 部署 Stackdriver DaemonSet 之后,你可以通过运行以下命令来查看日志代理的部署状态:
kubectl get ds --all-namespaces
如果你的集群中有 3 个节点,则输出应类似于如下:
NAMESPACE NAME DESIRED CURRENT READY NODE-SELECTOR AGE
...
default fluentd-gcp-v2.0 3 3 3 beta.kubernetes.io/fluentd-ds-ready=true 5m
...
要了解使用 Stackdriver 进行日志记录的工作方式,请考虑以下具有日志生成的 pod 定义 counter-pod.yaml :
apiVersion : v1
kind : Pod
metadata :
name : counter
spec :
containers :
- name : count
image : busybox
args : [/bin/sh, -c,
'i=0; while true; do echo "$i: $(date)"; i=$((i+1)); sleep 1; done' ]
这个 pod 定义里有一个容器,该容器运行一个 bash 脚本,脚本每秒写一次计数器的值和日期时间,并无限期地运行。
让我们在默认命名空间中创建此 pod。
kubectl apply -f https://k8s.io/examples/debug/counter-pod.yaml
你可以观察到正在运行的 pod:
NAME READY STATUS RESTARTS AGE
counter 1/1 Running 0 5m
在短时间内,你可以观察到 "pending" 的 pod 的状态,因为 kubelet 必须先下载容器镜像。
当 pod 状态变为 Running 时,你可以使用 kubectl logs 命令查看此 counter pod 的输出。
0: Mon Jan 1 00:00:00 UTC 2001
1: Mon Jan 1 00:00:01 UTC 2001
2: Mon Jan 1 00:00:02 UTC 2001
...
正如日志概览所述,此命令从容器日志文件中获取日志项。
如果该容器被 Kubernetes 杀死然后重新启动,你仍然可以访问前一个容器的日志。
但是,如果将 Pod 从节点中驱逐,则日志文件会丢失。让我们通过删除当前运行的 counter 容器来演示这一点:
kubectl delete pod counter
pod "counter" deleted
然后重建它:
kubectl create -f https://k8s.io/examples/debug/counter-pod.yaml
pod/counter created
一段时间后,你可以再次从 counter pod 访问日志:
0: Mon Jan 1 00:01:00 UTC 2001
1: Mon Jan 1 00:01:01 UTC 2001
2: Mon Jan 1 00:01:02 UTC 2001
...
如预期的那样,日志中仅出现最近的日志记录。
但是,对于实际应用程序,你可能希望能够访问所有容器的日志,特别是出于调试的目的。
这就是先前启用的 Stackdriver 日志机制可以提供帮助的地方。
查看日志 Stackdriver 日志代理为每个日志项关联元数据,供你在后续的查询中只选择感兴趣的消息:
例如,来自某个特定 Pod 的消息。
元数据最重要的部分是资源类型和日志名称。
容器日志的资源类型为 container,在用户界面中名为 GKE Containers(即使 Kubernetes 集群不在 Google Kubernetes Engine 上)。
日志名称是容器的名称,因此,如果你有一个包含两个容器的 pod,在 spec 中名称定义为 container_1 和 container_2,则它们的日志的名称分别为 container_1 和 container_2。
系统组件的资源类型为 compute,在接口中名为 GCE VM Instance。
系统组件的日志名称是固定的。
对于 Google Kubernetes Engine 节点,系统组件中的每个日志项都具有以下日志名称之一:
你可以在Stackdriver 专用页面
上了解有关查看日志的更多信息。
查看日志的一种可能方法是使用 Google Cloud SDK
中的 gcloud logging
命令行接口。
它使用 Stackdriver 日志机制的
过滤语法 查询特定日志。
例如,你可以运行以下命令:
gcloud beta logging read 'logName="projects/$YOUR_PROJECT_ID/logs/count"' --format json | jq '.[].textPayload'
...
"2: Mon Jan 1 00:01:02 UTC 2001\n"
"1: Mon Jan 1 00:01:01 UTC 2001\n"
"0: Mon Jan 1 00:01:00 UTC 2001\n"
...
"2: Mon Jan 1 00:00:02 UTC 2001\n"
"1: Mon Jan 1 00:00:01 UTC 2001\n"
"0: Mon Jan 1 00:00:00 UTC 2001\n"
如你所见,尽管 kubelet 已经删除了第一个容器的日志,日志中仍会包含 counter
容器第一次和第二次运行时输出的消息。
导出日志 你可以将日志导出到 Google Cloud Storage 或
BigQuery 进行进一步的分析。
Stackdriver 日志机制提供了接收器(Sink)的概念,你可以在其中指定日志项的存放地。
可在 Stackdriver 导出日志页面
上获得更多信息。
配置 Stackdriver 日志代理 有时默认的 Stackdriver 日志机制安装可能无法满足你的需求,例如:
你可能需要添加更多资源,因为默认的行为表现无法满足你的需求。 你可能需要引入额外的解析机制以便从日志消息中提取更多元数据,例如严重性或源代码引用。 你可能想要将日志不仅仅发送到 Stackdriver 或仅将部分日志发送到 Stackdriver。 在这种情况下,你需要更改 DaemonSet 和 ConfigMap 的参数。
先决条件 如果使用的是 GKE,并且集群中启用了 Stackdriver 日志机制,则无法更改其配置,
因为它是由 GKE 管理和支持的。
但是,你可以禁用默认集成的日志机制并部署自己的。
说明: 你将需要自己支持和维护新部署的配置了:更新映像和配置、调整资源等等。
若要禁用默认的日志记录集成,请使用以下命令:
gcloud beta container clusters update --logging-service=none CLUSTER
你可以在部署部分 中找到有关如何将 Stackdriver 日志代理安装到
正在运行的集群中的说明。
更改 DaemonSet 参数 当集群中有 Stackdriver 日志机制的 DaemonSet 时,你只需修改其 spec 中的
template 字段,daemonset 控制器将为你更新 Pod。
例如,假设你按照上面的描述已经安装了 Stackdriver 日志机制。
现在,你想更改内存限制,来给 fluentd 提供的更多内存,从而安全地处理更多日志。
获取集群中运行的 DaemonSet 的 spec:
kubectl get ds fluentd-gcp-v2.0 --namespace kube-system -o yaml > fluentd-gcp-ds.yaml
然后在 spec 文件中编辑资源需求,并使用以下命令更新 apiserver 中的 DaemonSet 对象:
kubectl replace -f fluentd-gcp-ds.yaml
一段时间后,Stackdriver 日志代理的 pod 将使用新配置重新启动。
更改 fluentd 参数 Fluentd 的配置存在 ConfigMap 对象中。
它实际上是一组合并在一起的配置文件。
你可以在官方网站 上了解 fluentd 的配置。
假设你要向配置添加新的解析逻辑,以便 fluentd 可以理解默认的 Python 日志记录格式。
一个合适的 fluentd 过滤器类似如下:
<filter reform.**>
type parser
format /^(?<severity>\w):(?<logger_name>\w):(?<log>.*)/
reserve_data true
suppress_parse_error_log true
key_name log
</filter>
现在,你需要将其放入配置中,并使 Stackdriver 日志代理感知它。
通过运行以下命令,获取集群中当前版本的 Stackdriver 日志机制的 ConfigMap:
kubectl get cm fluentd-gcp-config --namespace kube-system -o yaml > fluentd-gcp-configmap.yaml
然后在 containers.input.conf 键的值中,在 source 部分之后插入一个新的过滤器。
说明: 顺序很重要。
在 apiserver 中更新 ConfigMap 比更新 DaemonSet 更复杂。
最好考虑 ConfigMap 是不可变的。
如果是这样,要更新配置,你应该使用新名称创建 ConfigMap,然后使用
上面的指南 将 DaemonSet 更改为指向它。
添加 fluentd 插件 Fluentd 用 Ruby 编写,并允许使用 plugins 扩展其功能。
如果要使用默认的 Stackdriver 日志机制容器镜像中未包含的插件,则必须构建自定义镜像。
假设你要为来自特定容器添加 Kafka 信息接收器,以进行其他处理。
你可以复用默认的容器镜像源 ,并仅添加少量更改:
将 Makefile 更改为指向你的容器仓库,例如 PREFIX=gcr.io/<your-project-id>。 将你的依赖项添加到 Gemfile 中,例如 gem 'fluent-plugin-kafka'。 然后在该目录运行 make build push。
在更新 DaemonSet 以使用新镜像后,你就可以使用在 fluentd 配置中安装的插件了。
4.10.3 - 在本地开发和调试服务 Kubernetes 应用程序通常由多个独立的服务组成,每个服务都在自己的容器中运行。
在远端的 Kubernetes 集群上开发和调试这些服务可能很麻烦,需要
在运行的容器上打开 Shell ,
然后在远端 Shell 中运行你所需的工具。
telepresence 是一种工具,用于在本地轻松开发和调试服务,同时将服务代理到远程 Kubernetes 集群。
使用 telepresence 可以为本地服务使用自定义工具(如调试器和 IDE),
并提供对 Configmap、Secret 和远程集群上运行的服务的完全访问。
本文档描述如何在本地使用 telepresence 开发和调试远程集群上运行的服务。
准备开始 打开终端,不带参数运行 telepresence,以打开 telepresence Shell。
这个 Shell 在本地运行,使你可以完全访问本地文件系统。
telepresence Shell 的使用方式多种多样。
例如,在你的笔记本电脑上写一个 Shell 脚本,然后直接在 Shell 中实时运行它。
你也可以在远端 Shell 上执行此操作,但这样可能无法使用首选的代码编辑器,并且在容器终止时脚本将被删除。
开发和调试现有的服务 在 Kubernetes 上开发应用程序时,通常对单个服务进行编程或调试。
服务可能需要访问其他服务以进行测试和调试。
一种选择是使用连续部署流水线,但即使最快的部署流水线也会在程序或调试周期中引入延迟。
使用 --swap-deployment 选项将现有部署与 Telepresence 代理交换。
交换允许你在本地运行服务并能够连接到远端的 Kubernetes 集群。
远端集群中的服务现在就可以访问本地运行的实例。
要运行 telepresence 并带有 --swap-deployment 选项,请输入:
telepresence --swap-deployment $DEPLOYMENT_NAME
这里的 $DEPLOYMENT_NAME 是你现有的部署名称。
运行此命令将生成 Shell。在该 Shell 中,启动你的服务。
然后,你就可以在本地对源代码进行编辑、保存并能看到更改立即生效。
你还可以在调试器或任何其他本地开发工具中运行服务。
接下来 如果你对实践教程感兴趣,请查看本教程 ,其中介绍了在 Google Kubernetes Engine 上本地开发 Guestbook 应用程序。
Telepresence 有多种代理选项 ,以满足你的各种情况。
要了解更多信息,请访问 Telepresence 网站 。
4.10.4 - 审计 FEATURE STATE: Kubernetes v1.20 [beta]
Kubernetes 审计(Auditing) 功能提供了与安全相关的、按时间顺序排列的记录集,
记录每个用户、使用 Kubernetes API 的应用以及控制面自身引发的活动。
审计功能使得集群管理员能够回答以下问题:
发生了什么? 什么时候发生的? 谁触发的? 活动发生在哪个(些)对象上? 在哪观察到的? 它从哪触发的? 活动的后续处理行为是什么? 审计记录最初产生于
kube-apiserver
内部。每个请求在不同执行阶段都会生成审计事件;这些审计事件会根据特定策略
被预处理并写入后端。策略确定要记录的内容和用来存储记录的后端。
当前的后端支持日志文件和 webhook。
每个请求都可被记录其相关的 阶段(stage) 。已定义的阶段有:
RequestReceived - 此阶段对应审计处理器接收到请求后,并且在委托给
其余处理器之前生成的事件。ResponseStarted - 在响应消息的头部发送后,响应消息体发送前生成的事件。
只有长时间运行的请求(例如 watch)才会生成这个阶段。ResponseComplete - 当响应消息体完成并且没有更多数据需要传输的时候。Panic - 当 panic 发生时生成。说明: 审计日志记录功能会增加 API server 的内存消耗,因为需要为每个请求存储审计所需的某些上下文。
此外,内存消耗取决于审计日志记录的配置。
审计策略 审计政策定义了关于应记录哪些事件以及应包含哪些数据的规则。
审计策略对象结构定义在
audit.k8s.io API 组
处理事件时,将按顺序与规则列表进行比较。第一个匹配规则设置事件的
审计级别(Audit Level) 。已定义的审计级别有:
None - 符合这条规则的日志将不会记录。Metadata - 记录请求的元数据(请求的用户、时间戳、资源、动词等等),
但是不记录请求或者响应的消息体。Request - 记录事件的元数据和请求的消息体,但是不记录响应的消息体。
这不适用于非资源类型的请求。RequestResponse - 记录事件的元数据,请求和响应的消息体。这不适用于非资源类型的请求。你可以使用 --audit-policy-file 标志将包含策略的文件传递给 kube-apiserver。
如果不设置该标志,则不记录事件。
注意 rules 字段 必须 在审计策略文件中提供。没有(0)规则的策略将被视为非法配置。
以下是一个审计策略文件的示例:
apiVersion : audit.k8s.io/v1 # This is required.
kind : Policy
# Don't generate audit events for all requests in RequestReceived stage.
omitStages :
- "RequestReceived"
rules :
# Log pod changes at RequestResponse level
- level : RequestResponse
resources :
- group : ""
# Resource "pods" doesn't match requests to any subresource of pods,
# which is consistent with the RBAC policy.
resources : ["pods" ]
# Log "pods/log", "pods/status" at Metadata level
- level : Metadata
resources :
- group : ""
resources : ["pods/log" , "pods/status" ]
# Don't log requests to a configmap called "controller-leader"
- level : None
resources :
- group : ""
resources : ["configmaps" ]
resourceNames : ["controller-leader" ]
# Don't log watch requests by the "system:kube-proxy" on endpoints or services
- level : None
users : ["system:kube-proxy" ]
verbs : ["watch" ]
resources :
- group : "" # core API group
resources : ["endpoints" , "services" ]
# Don't log authenticated requests to certain non-resource URL paths.
- level : None
userGroups : ["system:authenticated" ]
nonResourceURLs :
- "/api*" # Wildcard matching.
- "/version"
# Log the request body of configmap changes in kube-system.
- level : Request
resources :
- group : "" # core API group
resources : ["configmaps" ]
# This rule only applies to resources in the "kube-system" namespace.
# The empty string "" can be used to select non-namespaced resources.
namespaces : ["kube-system" ]
# Log configmap and secret changes in all other namespaces at the Metadata level.
- level : Metadata
resources :
- group : "" # core API group
resources : ["secrets" , "configmaps" ]
# Log all other resources in core and extensions at the Request level.
- level : Request
resources :
- group : "" # core API group
- group : "extensions" # Version of group should NOT be included.
# A catch-all rule to log all other requests at the Metadata level.
- level : Metadata
# Long-running requests like watches that fall under this rule will not
# generate an audit event in RequestReceived.
omitStages :
- "RequestReceived"
你可以使用最低限度的审计策略文件在 Metadata 级别记录所有请求:
# 在 Metadata 级别为所有请求生成日志
apiVersion : audit.k8s.io/v1beta1
kind : Policy
rules :
- level : Metadata
如果你在打磨自己的审计配置文件,你可以使用为 Google Container-Optimized OS
设计的审计配置作为出发点。你可以参考
configure-helper.sh
脚本,该脚本能够生成审计策略文件。你可以直接在脚本中看到审计策略的绝大部份内容。
审计后端 审计后端实现将审计事件导出到外部存储。Kube-apiserver 默认提供两个后端:
Log 后端,将事件写入到文件系统 Webhook 后端,将事件发送到外部 HTTP API 在这两种情况下,审计事件结构均由 audit.k8s.io API 组中的 API 定义。
对于 Kubernetes v1.20.15,该 API 的当前版本是
v1 .
说明: 对于 patch 请求,请求的消息体需要是设定 patch 操作的 JSON 所构成的一个串,
而不是一个完整的 Kubernetes API 对象 JSON 串。
例如,以下的示例是一个合法的 patch 请求消息体,该请求对应
/apis/batch/v1/namespaces/some-namespace/jobs/some-job-name。
[
{
"op" : "replace" ,
"path" : "/spec/parallelism" ,
"value" : 0
},
{
"op" : "remove" ,
"path" : "/spec/template/spec/containers/0/terminationMessagePolicy"
}
]
Log 后端 Log 后端将审计事件写入 JSONlines 格式的文件。
你可以使用以下 kube-apiserver 标志配置 Log 审计后端:
--audit-log-path 指定用来写入审计事件的日志文件路径。不指定此标志会禁用日志后端。- 意味着标准化--audit-log-maxage 定义保留旧审计日志文件的最大天数--audit-log-maxbackup 定义要保留的审计日志文件的最大数量--audit-log-maxsize 定义审计日志文件的最大大小(兆字节)如果你的集群控制面以 Pod 的形式运行 kube-apiserver,记得要通过 hostPath
卷来访问策略文件和日志文件所在的目录,这样审计记录才会持久保存下来。例如:
--audit-policy-file= /etc/kubernetes/audit-policy.yaml
--audit-log-path= /var/log/audit.log
接下来挂载数据卷:
volumeMounts :
- mountPath : /etc/kubernetes/audit-policy.yaml
name : audit
readOnly : true
- mountPath : /var/log/audit.log
name : audit-log
readOnly : false
最后配置 hostPath:
- name : audit
hostPath :
path : /etc/kubernetes/audit-policy.yaml
type : File
- name : audit-log
hostPath :
path : /var/log/audit.log
type : FileOrCreate
Webhook 后端 Webhook 后端将审计事件发送到远程 Web API,该远程 API 应该暴露与 kube-apiserver
形式相同的 API,包括其身份认证机制。你可以使用如下 kube-apiserver 标志来配置
Webhook 审计后端:
--audit-webhook-config-file 设置 Webhook 配置文件的路径。Webhook 配置文件实际上是一个
kubeconfig 文件 。--audit-webhook-initial-backoff 指定在第一次失败后重发请求等待的时间。随后的请求将以指数退避重试。Webhook 配置文件使用 kubeconfig 格式指定服务的远程地址和用于连接它的凭据。
事件批处理 日志和 Webhook 后端都支持批处理。以 Webhook 为例,以下是可用参数列表。要获取日志
后端的同样参数,请在参数名称中将 webhook 替换为 log。
默认情况下,在 webhook 中批处理是被启用的,在 log 中批处理是被禁用的。
同样,默认情况下,在 webhook 中启用带宽限制,在 log 中禁用带宽限制。
--audit-webhook-mode 定义缓存策略,可选值如下:batch - 以批处理缓存事件和异步的过程。这是默认值。blocking - 在 API 服务器处理每个单独事件时,阻塞其响应。blocking-strict - 与 blocking 相同,不过当审计日志在 RequestReceived 阶段
失败时,整个 API 服务请求会失效。以下参数仅用于 batch 模式。
--audit-webhook-batch-buffer-size 定义 batch 之前要缓存的事件数。
如果传入事件的速率溢出缓存区,则会丢弃事件。--audit-webhook-batch-max-size 定义一个 batch 中的最大事件数。--audit-webhook-batch-max-wait 无条件 batch 队列中的事件前等待的最大事件。--audit-webhook-batch-throttle-qps 每秒生成的最大批次数。--audit-webhook-batch-throttle-burst 在达到允许的 QPS 前,同一时刻允许存在的最大 batch 生成数。参数调整 需要设置参数以适应 API 服务器上的负载。
例如,如果 kube-apiserver 每秒收到 100 个请求,并且每个请求仅在 ResponseStarted
和 ResponseComplete 阶段进行审计,则应该考虑每秒生成约 200 个审计事件。
假设批处理中最多有 100 个事件,则应将限制级别设置为每秒至少 2 个查询。
假设后端最多需要 5 秒钟来写入事件,你应该设置缓冲区大小以容纳最多 5 秒的事件,
即 10 个 batch,即 1000 个事件。
但是,在大多数情况下,默认参数应该足够了,你不必手动设置它们。
你可以查看 kube-apiserver 公开的以下 Prometheus 指标,并在日志中监控审计子系统的状态。
apiserver_audit_event_total 包含所有暴露的审计事件数量的指标。apiserver_audit_error_total 在暴露时由于发生错误而被丢弃的事件的数量。日志条目截断 日志后端和 Webhook 后端都支持限制所输出的事件的尺寸。
例如,下面是可以为日志后端配置的标志列表:
audit-log-truncate-enabled:是否弃用事件和批次的截断处理。audit-log-truncate-max-batch-size:向下层后端发送的各批次的最大尺寸字节数。audit-log-truncate-max-event-size:向下层后端发送的审计事件的最大尺寸字节数。默认情况下,截断操作在 webhook 和 log 后端都是被禁用的,集群管理员需要设置
audit-log-truncate-enabled 或 audit-webhook-truncate-enabled 标志来启用此操作。
接下来 4.10.5 - 应用故障排查 本指南帮助用户调试那些部署到 Kubernetes 上后没有正常运行的应用。
本指南 并非 指导用户如何调试集群。
如果想调试集群的话,请参阅这里 。
诊断问题 故障排查的第一步是先给问题分类。问题是什么?是关于 Pods、Replication Controller 还是 Service?
调试 Pods 调试 Pod 的第一步是查看 Pod 信息。用如下命令查看 Pod 的当前状态和最近的事件:
kubectl describe pods ${ POD_NAME }
查看一下 Pod 中的容器所处的状态。这些容器的状态都是 Running 吗?最近有没有重启过?
后面的调试都是要依靠 Pod 的状态的。
Pod 停滞在 Pending 状态 如果一个 Pod 停滞在 Pending 状态,表示 Pod 没有被调度到节点上。通常这是因为
某种类型的资源不足导致无法调度。
查看上面的 kubectl describe ... 命令的输出,其中应该显示了为什么没被调度的原因。
常见原因如下:
资源不足 :
你可能耗尽了集群上所有的 CPU 或内存。此时,你需要删除 Pod、调整资源请求或者为集群添加节点。
更多信息请参阅计算资源文档
使用了 hostPort :
如果绑定 Pod 到 hostPort,那么能够运行该 Pod 的节点就有限了。
多数情况下,hostPort 是非必要的,而应该采用 Service 对象来暴露 Pod。
如果确实需要使用 hostPort,那么集群中节点的个数就是所能创建的 Pod
的数量上限。
Pod 停滞在 Waiting 状态 如果 Pod 停滞在 Waiting 状态,则表示 Pod 已经被调度到某工作节点,但是无法在该节点上运行。
同样,kubectl describe ... 命令的输出可能很有用。
Waiting 状态的最常见原因是拉取镜像失败。要检查的有三个方面:
确保镜像名字拼写正确 确保镜像已被推送到镜像仓库 用手动命令 docker pull <镜像> 试试看镜像是否可拉取 Pod 处于 Crashing 或别的不健康状态 一旦 Pod 被调度,就可以采用
调试运行中的 Pod
中的方法来进一步调试。
Pod 处于 Running 态但是没有正常工作 如果 Pod 行为不符合预期,很可能 Pod 描述(例如你本地机器上的 mypod.yaml)中有问题,
并且该错误在创建 Pod 时被忽略掉,没有报错。
通常,Pod 的定义中节区嵌套关系错误、字段名字拼错的情况都会引起对应内容被忽略掉。
例如,如果你误将 command 写成 commnd,Pod 虽然可以创建,但它不会执行
你期望它执行的命令行。
可以做的第一件事是删除你的 Pod,并尝试带有 --validate 选项重新创建。
例如,运行 kubectl apply --validate -f mypod.yaml。
如果 command 被误拼成 commnd,你将会看到下面的错误信息:
I0805 10:43:25.129850 46757 schema.go:126] unknown field: commnd
I0805 10:43:25.129973 46757 schema.go:129] this may be a false alarm, see https://github.com/kubernetes/kubernetes/issues/6842
pods/mypod
接下来就要检查的是 API 服务器上的 Pod 与你所期望创建的是否匹配
(例如,你原本使用本机上的一个 YAML 文件来创建 Pod)。
例如,运行 kubectl get pods/mypod -o yaml > mypod-on-apiserver.yaml,之后
手动比较 mypod.yaml 与从 API 服务器取回的 Pod 描述。
从 API 服务器处获得的 YAML 通常包含一些创建 Pod 所用的 YAML 中不存在的行,这是正常的。
不过,如果如果源文件中有些行在 API 服务器版本中不存在,则意味着
Pod 规约是有问题的。
调试副本控制器 副本控制器相对比较简单直接。它们要么能创建 Pod,要么不能。
如果不能创建 Pod,请参阅上述说明 调试 Pod。
你也可以使用 kubectl describe rc ${CONTROLLER_NAME} 命令来检视副本控制器相关的事件。
调试服务 服务支持在多个 Pod 间负载均衡。
有一些常见的问题可以造成服务无法正常工作。
以下说明将有助于调试服务的问题。
首先,验证服务是否有端点。对于每一个 Service 对象,API 服务器为其提供
对应的 endpoints 资源。
通过如下命令可以查看 endpoints 资源:
kubectl get endpoints ${ SERVICE_NAME }
确保 Endpoints 与服务成员 Pod 个数一致。
例如,如果你的 Service 用来运行 3 个副本的 nginx 容器,你应该会在服务的 Endpoints
中看到 3 个不同的 IP 地址。
服务缺少 Endpoints 如果没有 Endpoints,请尝试使用 Service 所使用的标签列出 Pod。
假定你的服务包含如下标签选择算符:
...
spec :
- selector :
name : nginx
type : frontend
你可以使用如下命令列出与选择算符相匹配的 Pod,并验证这些 Pod 是否归属于创建的服务:
kubectl get pods --selector= name = nginx,type= frontend
如果 Pod 列表符合预期,但是 Endpoints 仍然为空,那么可能暴露的端口不正确。
如果服务指定了 containerPort,但是所选中的 Pod 没有列出该端口,这些 Pod
不会被添加到 Endpoints 列表。
验证 Pod 的 containerPort 与服务的 targetPort 是否匹配。
网络流量未被转发 如果你可以连接到服务上,但是连接立即被断开了,并且在 Endpoints 列表中有末端表项,
可能是代理无法连接到 Pod。
要检查的有以下三项:
Pod 工作是否正常? 看一下重启计数,并参阅调试 Pod ; 是否可以直接连接到 Pod?获取 Pod 的 IP 地址,然后尝试直接连接到该 IP; 应用是否在配置的端口上进行服务?Kubernetes 不进行端口重映射,所以如果应用在
8080 端口上服务,那么 containerPort 字段就要设定为 8080。 接下来 如果上述方法都不能解决你的问题,请按照
调试服务文档 中的介绍,
确保你的 Service 处于 Running 态,有 Endpoints 被创建,Pod 真的在提供服务;
DNS 服务已配置并正常工作,iptables 规则也以安装并且 kube-proxy 也没有异常行为。
你也可以访问故障排查文档 来获取更多信息。
4.10.6 - 应用自测与调试 运行应用时,不可避免的需要定位问题。
前面我们介绍了如何使用 kubectl get pods 来查询 pod 的简单信息。
除此之外,还有一系列的方法来获取应用的更详细信息。
使用 kubectl describe pod 命令获取 Pod 详情 与之前的例子类似,我们使用一个 Deployment 来创建两个 Pod。
apiVersion : apps/v1
kind : Deployment
metadata :
name : nginx-deployment
spec :
selector :
matchLabels :
app : nginx
replicas : 2
template :
metadata :
labels :
app : nginx
spec :
containers :
- name : nginx
image : nginx
resources :
limits :
memory : "128Mi"
cpu : "500m"
ports :
- containerPort : 80
使用如下命令创建 Deployment:
kubectl apply -f https://k8s.io/examples/application/nginx-with-request.yaml
deployment.apps/nginx-deployment created
使用如下命令查看 Pod 状态:
NAME READY STATUS RESTARTS AGE
nginx-deployment-1006230814-6winp 1/1 Running 0 11s
nginx-deployment-1006230814-fmgu3 1/1 Running 0 11s
我们可以使用 kubectl describe pod 命令来查询每个 Pod 的更多信息,比如:
kubectl describe pod nginx-deployment-1006230814-6winp
Name: nginx-deployment-1006230814-6winp
Namespace: default
Node: kubernetes-node-wul5/10.240.0.9
Start Time: Thu, 24 Mar 2016 01:39:49 +0000
Labels: app=nginx,pod-template-hash=1006230814
Annotations: kubernetes.io/created-by={"kind":"SerializedReference","apiVersion":"v1","reference":{"kind":"ReplicaSet","namespace":"default","name":"nginx-deployment-1956810328","uid":"14e607e7-8ba1-11e7-b5cb-fa16" ...
Status: Running
IP: 10.244.0.6
Controllers: ReplicaSet/nginx-deployment-1006230814
Containers:
nginx:
Container ID: docker://90315cc9f513c724e9957a4788d3e625a078de84750f244a40f97ae355eb1149
Image: nginx
Image ID: docker://6f62f48c4e55d700cf3eb1b5e33fa051802986b77b874cc351cce539e5163707
Port: 80/TCP
QoS Tier:
cpu: Guaranteed
memory: Guaranteed
Limits:
cpu: 500m
memory: 128Mi
Requests:
memory: 128Mi
cpu: 500m
State: Running
Started: Thu, 24 Mar 2016 01:39:51 +0000
Ready: True
Restart Count: 0
Environment: <none>
Mounts:
/var/run/secrets/kubernetes.io/serviceaccount from default-token-5kdvl (ro)
Conditions:
Type Status
Initialized True
Ready True
PodScheduled True
Volumes:
default-token-4bcbi:
Type: Secret (a volume populated by a Secret)
SecretName: default-token-4bcbi
Optional: false
QoS Class: Guaranteed
Node-Selectors: <none>
Tolerations: <none>
Events:
FirstSeen LastSeen Count From SubobjectPath Type Reason Message
--------- -------- ----- ---- ------------- -------- ------ -------
54s 54s 1 {default-scheduler } Normal Scheduled Successfully assigned nginx-deployment-1006230814-6winp to kubernetes-node-wul5
54s 54s 1 {kubelet kubernetes-node-wul5} spec.containers{nginx} Normal Pulling pulling image "nginx"
53s 53s 1 {kubelet kubernetes-node-wul5} spec.containers{nginx} Normal Pulled Successfully pulled image "nginx"
53s 53s 1 {kubelet kubernetes-node-wul5} spec.containers{nginx} Normal Created Created container with docker id 90315cc9f513
53s 53s 1 {kubelet kubernetes-node-wul5} spec.containers{nginx} Normal Started Started container with docker id 90315cc9f513
这里可以看到容器和 Pod 的标签、资源需求等配置信息,还可以看到状态、就绪态、
重启次数、事件等状态信息。
容器状态是 Waiting、Running 和 Terminated 之一。
根据状态的不同,还有对应的额外的信息 —— 在这里你可以看到,
对于处于运行状态的容器,系统会告诉你容器的启动时间。
Ready 指示是否通过了最后一个就绪态探测。
(在本例中,容器没有配置就绪态探测;如果没有配置就绪态探测,则假定容器已经就绪。)
Restart Count 告诉你容器已重启的次数;
这些信息对于定位配置了 “Always” 重启策略的容器持续崩溃问题非常有用。
目前,唯一与 Pod 有关的状态是 Ready 状况,该状况表明 Pod 能够为请求提供服务,
并且应该添加到相应服务的负载均衡池中。
最后,你还可以看到与 Pod 相关的近期事件。
系统通过指示第一次和最后一次看到事件以及看到该事件的次数来压缩多个相同的事件。
“From” 标明记录事件的组件,
“SubobjectPath” 告诉你引用了哪个对象(例如 Pod 中的容器),
“Reason” 和 “Message” 告诉你发生了什么。
例子: 调试 Pending 状态的 Pod 可以使用事件来调试的一个常见的场景是,你创建 Pod 无法被调度到任何节点。
比如,Pod 请求的资源比较多,没有任何一个节点能够满足,或者它指定了一个标签,没有节点可匹配。
假定我们创建之前的 Deployment 时指定副本数是 5(不再是 2),并且请求 600 毫核(不再是 500),
对于一个 4 个节点的集群,若每个节点只有 1 个 CPU,这时至少有一个 Pod 不能被调度。
(需要注意的是,其他集群插件 Pod,比如 fluentd、skydns 等等会在每个节点上运行,
如果我们需求 1000 毫核,将不会有 Pod 会被调度。)
NAME READY STATUS RESTARTS AGE
nginx-deployment-1006230814-6winp 1/1 Running 0 7m
nginx-deployment-1006230814-fmgu3 1/1 Running 0 7m
nginx-deployment-1370807587-6ekbw 1/1 Running 0 1m
nginx-deployment-1370807587-fg172 0/1 Pending 0 1m
nginx-deployment-1370807587-fz9sd 0/1 Pending 0 1m
为了查找 Pod nginx-deployment-1370807587-fz9sd 没有运行的原因,我们可以使用
kubectl describe pod 命令描述 Pod,查看其事件:
kubectl describe pod nginx-deployment-1370807587-fz9sd
Name: nginx-deployment-1370807587-fz9sd
Namespace: default
Node: /
Labels: app=nginx,pod-template-hash=1370807587
Status: Pending
IP:
Controllers: ReplicaSet/nginx-deployment-1370807587
Containers:
nginx:
Image: nginx
Port: 80/TCP
QoS Tier:
memory: Guaranteed
cpu: Guaranteed
Limits:
cpu: 1
memory: 128Mi
Requests:
cpu: 1
memory: 128Mi
Environment Variables:
Volumes:
default-token-4bcbi:
Type: Secret (a volume populated by a Secret)
SecretName: default-token-4bcbi
Events:
FirstSeen LastSeen Count From SubobjectPath Type Reason Message
--------- -------- ----- ---- ------------- -------- ------ -------
1m 48s 7 {default-scheduler } Warning FailedScheduling pod (nginx-deployment-1370807587-fz9sd) failed to fit in any node
fit failure on node (kubernetes-node-6ta5): Node didn't have enough resource: CPU, requested: 1000, used: 1420, capacity: 2000
fit failure on node (kubernetes-node-wul5): Node didn't have enough resource: CPU, requested: 1000, used: 1100, capacity: 2000
这里你可以看到由调度器记录的事件,它表明了 Pod 不能被调度的原因是 FailedScheduling(也可能是其他值)。
其 message 部分表明没有任何节点拥有足够多的资源。
要纠正这种情况,可以使用 kubectl scale 更新 Deployment,以指定 4 个或更少的副本。
(或者你可以让 Pod 继续保持这个状态,这是无害的。)
你在 kubectl describe pod 结尾处看到的事件都保存在 etcd 中,
并提供关于集群中正在发生的事情的高级信息。
如果需要列出所有事件,可使用命令:
但是,需要注意的是,事件是区分名字空间的。
如果你对某些名字空间域的对象(比如 my-namespace 名字下的 Pod)的事件感兴趣,
你需要显式地在命令行中指定名字空间:
kubectl get events --namespace= my-namespace
查看所有 namespace 的事件,可使用 --all-namespaces 参数。
除了 kubectl describe pod 以外,另一种获取 Pod 额外信息(除了 kubectl get pod)的方法
是给 kubectl get pod 增加 -o yaml 输出格式参数。
该命令将以 YAML 格式为你提供比 kubectl describe pod 更多的信息 —— 实际上是系统拥有的关于 Pod 的所有信息。
在这里,你将看到注解(没有标签限制的键值元数据,由 Kubernetes 系统组件在内部使用)、
重启策略、端口和卷等。
kubectl get pod nginx-deployment-1006230814-6winp -o yaml
apiVersion : v1
kind : Pod
metadata :
annotations :
kubernetes.io/created-by : |
{"kind" :"SerializedReference" ,"apiVersion" :"v1" ,"reference" :{"kind" :"ReplicaSet" ,"namespace" :"default" ,"name" :"nginx-deployment-1006230814" ,"uid" :"4c84c175-f161-11e5-9a78-42010af00005" ,"apiVersion" :"extensions" ,"resourceVersion" :"133434" }}
creationTimestamp : 2016-03-24T01:39:50Z
generateName : nginx-deployment-1006230814-
labels :
app : nginx
pod-template-hash : "1006230814"
name : nginx-deployment-1006230814-6winp
namespace : default
resourceVersion : "133447"
uid : 4c879808-f161-11e5-9a78-42010af00005
spec :
containers :
- image : nginx
imagePullPolicy : Always
name : nginx
ports :
- containerPort : 80
protocol : TCP
resources :
limits :
cpu : 500m
memory : 128Mi
requests :
cpu : 500m
memory : 128Mi
terminationMessagePath : /dev/termination-log
volumeMounts :
- mountPath : /var/run/secrets/kubernetes.io/serviceaccount
name : default-token-4bcbi
readOnly : true
dnsPolicy : ClusterFirst
nodeName : kubernetes-node-wul5
restartPolicy : Always
securityContext : {}
serviceAccount : default
serviceAccountName : default
terminationGracePeriodSeconds : 30
volumes :
- name : default-token-4bcbi
secret :
secretName : default-token-4bcbi
status :
conditions :
- lastProbeTime : null
lastTransitionTime : 2016-03-24T01:39:51Z
status : "True"
type : Ready
containerStatuses :
- containerID : docker://90315cc9f513c724e9957a4788d3e625a078de84750f244a40f97ae355eb1149
image : nginx
imageID : docker://6f62f48c4e55d700cf3eb1b5e33fa051802986b77b874cc351cce539e5163707
lastState : {}
name : nginx
ready : true
restartCount : 0
state :
running :
startedAt : 2016-03-24T01:39:51Z
hostIP : 10.240.0.9
phase : Running
podIP : 10.244.0.6
startTime : 2016-03-24T01:39:49Z
示例:调试宕机或无法联系的节点 有时候,在调试时,查看节点的状态是很有用的 —— 例如,因为你已经注意到节点上运行的 Pod 的奇怪行为,
或者想了解为什么 Pod 不会调度到节点上。
与 Pod 一样,你可以使用 kubectl describe node 和 kubectl get node -o yaml 来查询节点的详细信息。
例如,如果某个节点宕机(与网络断开连接,或者 kubelet 挂掉无法重新启动等等),你将看到以下情况。
请注意显示节点未就绪的事件,也请注意 Pod 不再运行(它们在5分钟未就绪状态后被驱逐)。
NAME STATUS ROLES AGE VERSION
kubernetes-node-861h NotReady <none> 1h v1.13.0
kubernetes-node-bols Ready <none> 1h v1.13.0
kubernetes-node-st6x Ready <none> 1h v1.13.0
kubernetes-node-unaj Ready <none> 1h v1.13.0
kubectl describe node kubernetes-node-861h
Name: kubernetes-node-861h
Role
Labels: kubernetes.io/arch=amd64
kubernetes.io/os=linux
kubernetes.io/hostname=kubernetes-node-861h
Annotations: node.alpha.kubernetes.io/ttl=0
volumes.kubernetes.io/controller-managed-attach-detach=true
Taints: <none>
CreationTimestamp: Mon, 04 Sep 2017 17:13:23 +0800
Phase:
Conditions:
Type Status LastHeartbeatTime LastTransitionTime Reason Message
---- ------ ----------------- ------------------ ------ -------
OutOfDisk Unknown Fri, 08 Sep 2017 16:04:28 +0800 Fri, 08 Sep 2017 16:20:58 +0800 NodeStatusUnknown Kubelet stopped posting node status.
MemoryPressure Unknown Fri, 08 Sep 2017 16:04:28 +0800 Fri, 08 Sep 2017 16:20:58 +0800 NodeStatusUnknown Kubelet stopped posting node status.
DiskPressure Unknown Fri, 08 Sep 2017 16:04:28 +0800 Fri, 08 Sep 2017 16:20:58 +0800 NodeStatusUnknown Kubelet stopped posting node status.
Ready Unknown Fri, 08 Sep 2017 16:04:28 +0800 Fri, 08 Sep 2017 16:20:58 +0800 NodeStatusUnknown Kubelet stopped posting node status.
Addresses: 10.240.115.55,104.197.0.26
Capacity:
cpu: 2
hugePages: 0
memory: 4046788Ki
pods: 110
Allocatable:
cpu: 1500m
hugePages: 0
memory: 1479263Ki
pods: 110
System Info:
Machine ID: 8e025a21a4254e11b028584d9d8b12c4
System UUID: 349075D1-D169-4F25-9F2A-E886850C47E3
Boot ID: 5cd18b37-c5bd-4658-94e0-e436d3f110e0
Kernel Version: 4.4.0-31-generic
OS Image: Debian GNU/Linux 8 (jessie)
Operating System: linux
Architecture: amd64
Container Runtime Version: docker://1.12.5
Kubelet Version: v1.6.9+a3d1dfa6f4335
Kube-Proxy Version: v1.6.9+a3d1dfa6f4335
ExternalID: 15233045891481496305
Non-terminated Pods: (9 in total)
Namespace Name CPU Requests CPU Limits Memory Requests Memory Limits
--------- ---- ------------ ---------- --------------- -------------
......
Allocated resources:
(Total limits may be over 100 percent, i.e., overcommitted.)
CPU Requests CPU Limits Memory Requests Memory Limits
------------ ---------- --------------- -------------
900m (60%) 2200m (146%) 1009286400 (66%) 5681286400 (375%)
Events: <none>
kubectl get node kubernetes-node-861h -o yaml
apiVersion : v1
kind : Node
metadata :
creationTimestamp : 2015-07-10T21:32:29Z
labels :
kubernetes.io/hostname : kubernetes-node-861h
name : kubernetes-node-861h
resourceVersion : "757"
selfLink : /api/v1/nodes/kubernetes-node-861h
uid : 2a69374e-274b-11e5-a234-42010af0d969
spec :
externalID : "15233045891481496305"
podCIDR : 10.244.0.0 /24
providerID : gce://striped-torus-760/us-central1-b/kubernetes-node-861h
status :
addresses :
- address : 10.240.115.55
type : InternalIP
- address : 104.197.0.26
type : ExternalIP
capacity :
cpu : "1"
memory : 3800808Ki
pods : "100"
conditions :
- lastHeartbeatTime : 2015-07-10T21:34:32Z
lastTransitionTime : 2015-07-10T21:35:15Z
reason : Kubelet stopped posting node status.
status : Unknown
type : Ready
nodeInfo :
bootID : 4e316776 -b40d-4f78-a4ea-ab0d73390897
containerRuntimeVersion : docker://Unknown
kernelVersion : 3.16.0-0. bpo.4-amd64
kubeProxyVersion : v0.21.1-185-gffc5a86098dc01
kubeletVersion : v0.21.1-185-gffc5a86098dc01
machineID : ""
osImage : Debian GNU/Linux 7 (wheezy)
systemUUID : ABE5F6B4-D44B-108B-C46A-24CCE16C8B6E
接下来 了解更多的调试工具:
4.10.7 - 故障诊断 有时候事情会出错。本指南旨在解决这些问题。它包含两个部分:
应用排错 -
针对部署代码到 Kubernetes 并想知道代码为什么不能正常运行的用户。集群排错 -
针对集群管理员以及 Kubernetes 集群表现异常的用户。你也应该查看所用发行版本 的已知问题。
获取帮助 如果你的问题在上述指南中没有得到答案,你还有另外几种方式从 Kubernetes 团队获得帮助。
问题 本网站上的文档针对回答各类问题进行了结构化组织和分类。
概念 部分解释 Kubernetes 体系结构以及每个组件的工作方式,
安装 部分提供了安装的实用说明。
任务 部分展示了如何完成常用任务,
教程 部分则提供对现实世界、特定行业或端到端开发场景的更全面的演练。
参考 部分提供了详细的
Kubernetes API 文档
和命令行 (CLI) 接口的文档,例如kubectl 。
求救!我的问题还没有解决!我现在需要帮助! Stack Overflow 社区中的其他人可能已经问过和你类似的问题,也可能能够帮助解决你的问题。
Kubernetes 团队还会监视带有 Kubernetes 标签的帖子 。
如果现有的问题对你没有帮助,请问一个新问题 !
Slack Kubernetes 社区中有很多人在 #kubernetes-users 这一 Slack 频道聚集。
Slack 需要注册;你可以请求一份邀请 ,
并且注册是对所有人开放的。欢迎你随时来问任何问题。
一旦注册了,就可以访问通过 Web 浏览器或者 Slack 专用的应用访问
Slack 上的 Kubernetes 组织 。
一旦你完成了注册,就可以浏览各种感兴趣主题的频道列表(一直在增长)。
例如,Kubernetes 新人可能还想加入
#kubernetes-novice
频道。又比如,开发人员应该加入
#kubernetes-dev
频道。
还有许多国家/地区语言频道。请随时加入这些频道以获得本地化支持和信息:
论坛 欢迎你加入 Kubernetes 官方论坛
discuss.kubernetes.io 。
Bugs 和功能请求 如果你发现一个看起来像 Bug 的问题,或者你想提出一个功能请求,请使用
Github 问题跟踪系统 。
在提交问题之前,请搜索现有问题列表以查看是否其中已涵盖你的问题。
如果提交 Bug,请提供如何重现问题的详细信息,例如:
Kubernetes 版本:kubectl version 云平台、OS 发行版、网络配置和 Docker 版本 重现问题的步骤 4.10.8 - 确定 Pod 失败的原因 本文介绍如何编写和读取容器的终止消息。
终止消息为容器提供了一种方法,可以将有关致命事件的信息写入某个位置,
在该位置可以通过仪表板和监控软件等工具轻松检索和显示致命事件。
在大多数情况下,您放入终止消息中的信息也应该写入
常规 Kubernetes 日志 。
准备开始
你必须拥有一个 Kubernetes 的集群,同时你的 Kubernetes 集群必须带有 kubectl 命令行工具。
如果你还没有集群,你可以通过 Minikube 构建一
个你自己的集群,或者你可以使用下面任意一个 Kubernetes 工具构建:
要获知版本信息,请输入
kubectl version.
读写终止消息 在本练习中,您将创建运行一个容器的 Pod。
配置文件指定在容器启动时要运行的命令。
apiVersion : v1
kind : Pod
metadata :
name : termination-demo
spec :
containers :
- name : termination-demo-container
image : debian
command : ["/bin/sh" ]
args : ["-c" , "sleep 10 && echo Sleep expired > /dev/termination-log" ]
基于 YAML 配置文件创建 Pod:kubectl create -f https://k8s.io/examples/debug/termination.yaml
YAML 文件中,在 cmd 和 args 字段,你可以看到容器休眠 10 秒然后将 "Sleep expired"
写入 /dev/termination-log 文件。
容器写完 "Sleep expired" 消息后就终止了。
显示 Pod 的信息:kubectl get pod termination-demo
重复前面的命令直到 Pod 不再运行。
显示 Pod 的详细信息:
kubectl get pod --output= yaml
输出结果包含 "Sleep expired" 消息:apiVersion : v1
kind : Pod
...
lastState :
terminated :
containerID : ...
exitCode : 0
finishedAt : ...
message : |
Sleep expired
...
使用 Go 模板过滤输出结果,使其只含有终止消息:
kubectl get pod termination-demo -o go-template= "{{range .status.containerStatuses}}{{.lastState.terminated.message}}{{end}}"
定制终止消息 Kubernetes 从容器的 terminationMessagePath 字段中指定的终止消息文件中检索终止消息,
默认值为 /dev/termination-log。
通过定制这个字段,您可以告诉 Kubernetes 使用不同的文件。
Kubernetes 使用指定文件中的内容在成功和失败时填充容器的状态消息。
在下例中,容器将终止消息写入 /tmp/my-log 给 Kubernetes 来接收:
apiVersion : v1
kind : Pod
metadata :
name : msg-path-demo
spec :
containers :
- name : msg-path-demo-container
image : debian
terminationMessagePath : "/tmp/my-log"
此外,用户可以设置容器的 terminationMessagePolicy 字段,以便进一步自定义。
此字段默认为 "File",这意味着仅从终止消息文件中检索终止消息。
通过将 terminationMessagePolicy 设置为 "FallbackToLogsOnError",你就可以告诉 Kubernetes,在容器因错误退出时,如果终止消息文件为空,则使用容器日志输出的最后一块作为终止消息。
日志输出限制为 2048 字节或 80 行,以较小者为准。
接下来 4.10.9 - 节点健康监测 节点问题探测器 是一个 DaemonSet ,
用来监控节点健康。它从各种守护进程收集节点问题,并以
NodeCondition 和
Event
的形式报告给 API 服务器。
它现在支持一些已知的内核问题检测,并将随着时间的推移,检测更多节点问题。
目前,Kubernetes 不会对节点问题检测器监测到的节点状态和事件采取任何操作。
将来可能会引入一个补救系统来处理这些节点问题。
更多信息请参阅 这里 。
准备开始
你必须拥有一个 Kubernetes 的集群,同时你的 Kubernetes 集群必须带有 kubectl 命令行工具。
如果你还没有集群,你可以通过 Minikube 构建一
个你自己的集群,或者你可以使用下面任意一个 Kubernetes 工具构建:
要获知版本信息,请输入
kubectl version.
局限性 节点问题检测器的内核问题检测现在只支持基于文件类型的内核日志。
它不支持像 journald 这样的命令行日志工具。 节点问题检测器的内核问题检测对内核日志格式有一定要求,现在它只适用于 Ubuntu 和 Debian。
不过将其扩展为支持其它日志格式 也很容易。 在 GCE 集群中启用/禁用 节点问题检测器在 gce 集群中以
集群插件的形式
默认启用。
你可以在运行 kube-up.sh 之前,以设置环境变量 KUBE_ENABLE_NODE_PROBLEM_DETECTOR 的形式启用/禁用它。
在其它环境中使用 要在 GCE 之外的其他环境中启用节点问题检测器,你可以使用 kubectl 或插件 pod。
Kubectl 这是在 GCE 之外启动节点问题检测器的推荐方法。
它的管理更加灵活,例如覆盖默认配置以使其适合你的环境或检测自定义节点问题。
步骤 1: node-problem-detector.yaml:apiVersion : apps/v1
kind : DaemonSet
metadata :
name : node-problem-detector-v0.1
namespace : kube-system
labels :
k8s-app : node-problem-detector
version : v0.1
kubernetes.io/cluster-service : "true"
spec :
selector :
matchLabels :
k8s-app : node-problem-detector
version : v0.1
kubernetes.io/cluster-service : "true"
template :
metadata :
labels :
k8s-app : node-problem-detector
version : v0.1
kubernetes.io/cluster-service : "true"
spec :
hostNetwork : true
containers :
- name : node-problem-detector
image : k8s.gcr.io/node-problem-detector:v0.1
securityContext :
privileged : true
resources :
limits :
cpu : "200m"
memory : "100Mi"
requests :
cpu : "20m"
memory : "20Mi"
volumeMounts :
- name : log
mountPath : /log
readOnly : true
volumes :
- name : log
hostPath :
path : /var/log/请注意保证你的系统日志路径与你的 OS 发行版相对应。
步骤 2: 执行 kubectl 来启动节点问题检测器: kubectl create -f https://k8s.io/examples/debug/node-problem-detector.yaml
插件 Pod 这适用于拥有自己的集群引导程序解决方案的用户,并且不需要覆盖默认配置。
他们可以利用插件 Pod 进一步自动化部署。
只需创建 node-problem-detector.yaml,并将其放在主节点上的插件 pod 目录
/etc/kubernetes/addons/node-problem-detector 下。
覆盖配置文件 构建节点问题检测器的 docker 镜像时,会嵌入
默认配置 。
不过,你可以像下面这样使用 ConfigMap
将其覆盖:
步骤 1: 在 config/ 中更改配置文件。步骤 2: 使用 kubectl create configmap node-problem-detector-config --from-file=config/ 创建 node-problem-detector-config 。步骤 3: 更改 node-problem-detector.yaml 以使用 ConfigMap:apiVersion : apps/v1
kind : DaemonSet
metadata :
name : node-problem-detector-v0.1
namespace : kube-system
labels :
k8s-app : node-problem-detector
version : v0.1
kubernetes.io/cluster-service : "true"
spec :
selector :
matchLabels :
k8s-app : node-problem-detector
version : v0.1
kubernetes.io/cluster-service : "true"
template :
metadata :
labels :
k8s-app : node-problem-detector
version : v0.1
kubernetes.io/cluster-service : "true"
spec :
hostNetwork : true
containers :
- name : node-problem-detector
image : k8s.gcr.io/node-problem-detector:v0.1
securityContext :
privileged : true
resources :
limits :
cpu : "200m"
memory : "100Mi"
requests :
cpu : "20m"
memory : "20Mi"
volumeMounts :
- name : log
mountPath : /log
readOnly : true
- name : config # Overwrite the config/ directory with ConfigMap volume
mountPath : /config
readOnly : true
volumes :
- name : log
hostPath :
path : /var/log/
- name : config # Define ConfigMap volume
configMap :
name : node-problem-detector-config步骤 4: 使用新的 yaml 文件重新创建节点问题检测器: kubectl delete -f https://k8s.io/examples/debug/node-problem-detector.yaml # If you have a node-problem-detector running
kubectl create -f https://k8s.io/examples/debug/node-problem-detector-configmap.yaml
请注意,此方法仅适用于通过 kubectl 启动的节点问题检测器。
由于插件管理器不支持ConfigMap,因此现在不支持对于作为集群插件运行的节点问题检测器的配置进行覆盖。
内核监视器 内核监视器 是节点问题检测器中的问题守护进程。它监视内核日志并按照预定义规则检测已知内核问题。
内核监视器根据 config/kernel-monitor.json 中的一组预定义规则列表匹配内核问题。
规则列表是可扩展的,你始终可以通过覆盖配置来扩展它。
添加新的 NodeCondition 你可以使用新的状态描述来扩展 config/kernel-monitor.json 中的 conditions 字段以支持新的节点状态。
{
"type" : "NodeConditionType" ,
"reason" : "CamelCaseDefaultNodeConditionReason" ,
"message" : "arbitrary default node condition message"
}
检测新的问题 你可以使用新的规则描述来扩展 config/kernel-monitor.json 中的 rules 字段以检测新问题。
{
"type" : "temporary/permanent" ,
"condition" : "NodeConditionOfPermanentIssue" ,
"reason" : "CamelCaseShortReason" ,
"message" : "regexp matching the issue in the kernel log"
}
更改日志路径 不同操作系统发行版的内核日志的可能不同。 config/kernel-monitor.json 中的 log 字段是容器内的日志路径。你始终可以修改配置使其与你的 OS 发行版匹配。
内核监视器使用 [Translator] 插件将内核日志转换为内部数据结构。
我们可以很容易为新的日志格式实现新的翻译器。
注意事项 我们建议在集群中运行节点问题检测器来监视节点运行状况。
但是,你应该知道这将在每个节点上引入额外的资源开销。一般情况下没有影响,因为:
内核日志生成相对较慢。 节点问题检测器有资源限制。 即使在高负载下,资源使用也是可以接受的。
(参阅 基准测试结果 ) 4.10.10 - 获取正在运行容器的 Shell 本文介绍怎样使用 kubectl exec 命令获取正在运行容器的 Shell。
准备开始
你必须拥有一个 Kubernetes 的集群,同时你的 Kubernetes 集群必须带有 kubectl 命令行工具。
如果你还没有集群,你可以通过 Minikube 构建一
个你自己的集群,或者你可以使用下面任意一个 Kubernetes 工具构建:
要获知版本信息,请输入
kubectl version.
获取容器的 Shell 在本练习中,你将创建包含一个容器的 Pod。容器运行 nginx 镜像。下面是 Pod 的配置文件:
apiVersion : v1
kind : Pod
metadata :
name : shell-demo
spec :
volumes :
- name : shared-data
emptyDir : {}
containers :
- name : nginx
image : nginx
volumeMounts :
- name : shared-data
mountPath : /usr/share/nginx/html
hostNetwork : true
dnsPolicy : Default
创建 Pod:
kubectl create -f https://k8s.io/examples/application/shell-demo.yaml
检查容器是否运行正常:
kubectl get pod shell-demo
获取正在运行容器的 Shell:
kubectl exec -it shell-demo -- /bin/bash
说明: 双破折号 "--" 用于将要传递给命令的参数与 kubectl 的参数分开。
在 shell 中,打印根目录:
在 shell 中,实验其他命令。下面是一些示例:
root@shell-demo:/# ls /
root@shell-demo:/# cat /proc/mounts
root@shell-demo:/# cat /proc/1/maps
root@shell-demo:/# apt-get update
root@shell-demo:/# apt-get install -y tcpdump
root@shell-demo:/# tcpdump
root@shell-demo:/# apt-get install -y lsof
root@shell-demo:/# lsof
root@shell-demo:/# apt-get install -y procps
root@shell-demo:/# ps aux
root@shell-demo:/# ps aux | grep nginx
编写 nginx 的 根页面 在看一下 Pod 的配置文件。该 Pod 有个 emptyDir 卷,容器将该卷挂载到了 /usr/share/nginx/html。
在 shell 中,在 /usr/share/nginx/html 目录创建一个 index.html 文件:
root@shell-demo:/# echo Hello shell demo > /usr/share/nginx/html/index.html
在 shell 中,向 nginx 服务器发送 GET 请求:
root@shell-demo:/# apt-get update
root@shell-demo:/# apt-get install curl
root@shell-demo:/# curl localhost
输出结果显示了你在 index.html 中写入的文本。
当用完 shell 后,输入 exit 退出。
在容器中运行单个命令 在普通的命令窗口(而不是 shell)中,打印环境运行容器中的变量:
kubectl exec shell-demo env
实验运行其他命令。下面是一些示例:
kubectl exec shell-demo ps aux
kubectl exec shell-demo ls /
kubectl exec shell-demo cat /proc/1/mounts
当 Pod 包含多个容器时打开 shell 如果 Pod 有多个容器,--container 或者 -c 可以在 kubectl exec 命令中指定容器。
例如,您有个名为 my-pod 的容器,该 Pod 有两个容器分别为 main-app 和 healper-app。
下面的命令将会打开一个 shell 访问 main-app 容器。
kubectl exec -it my-pod --container main-app -- /bin/bash
接下来 4.10.11 - 调试 Init 容器 此页显示如何核查与 Init 容器执行相关的问题。
下面的示例命令行将 Pod 称为 <pod-name>,而 Init 容器称为 <init-container-1> 和
<init-container-2>。
准备开始
你必须拥有一个 Kubernetes 的集群,同时你的 Kubernetes 集群必须带有 kubectl 命令行工具。
如果你还没有集群,你可以通过 Minikube 构建一
个你自己的集群,或者你可以使用下面任意一个 Kubernetes 工具构建:
要获知版本信息,请输入
kubectl version.
检查 Init 容器的状态 显示你的 Pod 的状态:
kubectl get pod <pod-name>
例如,状态 Init:1/2 表明两个 Init 容器中的一个已经成功完成:
NAME READY STATUS RESTARTS AGE
<pod-name> 0/1 Init:1/2 0 7s
更多状态值及其含义请参考理解 Pod 的状态 。
获取 Init 容器详情 查看 Init 容器运行的更多详情:
kubectl describe pod <pod-name>
例如,对于包含两个 Init 容器的 Pod 可能显示如下信息:
Init Containers:
<init-container-1>:
Container ID: ...
...
State: Terminated
Reason: Completed
Exit Code: 0
Started: ...
Finished: ...
Ready: True
Restart Count: 0
...
<init-container-2>:
Container ID: ...
...
State: Waiting
Reason: CrashLoopBackOff
Last State: Terminated
Reason: Error
Exit Code: 1
Started: ...
Finished: ...
Ready: False
Restart Count: 3
...
你还可以通过编程方式读取 Pod Spec 上的 status.initContainerStatuses 字段,了解 Init 容器的状态:
kubectl get pod nginx --template '{{.status.initContainerStatuses}}'
此命令将返回与原始 JSON 中相同的信息.
通过 Init 容器访问日志 与 Pod 名称一起传递 Init 容器名称,以访问容器的日志。
kubectl logs <pod-name> -c <init-container-2>
运行 Shell 脚本的 Init 容器在执行 Shell 脚本时输出命令本身。
例如,你可以在 Bash 中通过在脚本的开头运行 set -x 来实现。
理解 Pod 的状态 以 Init: 开头的 Pod 状态汇总了 Init 容器执行的状态。
下表介绍调试 Init 容器时可能看到的一些状态值示例。
状态 含义 Init:N/MPod 包含 M 个 Init 容器,其中 N 个已经运行完成。 Init:ErrorInit 容器已执行失败。 Init:CrashLoopBackOffInit 容器执行总是失败。 PendingPod 还没有开始执行 Init 容器。 PodInitializing or RunningPod 已经完成执行 Init 容器。
4.10.12 - 调试 Pods 和 ReplicationControllers 此页面展示如何调试 Pod 和 ReplicationController。
准备开始
你必须拥有一个 Kubernetes 的集群,同时你的 Kubernetes 集群必须带有 kubectl 命令行工具。
如果你还没有集群,你可以通过 Minikube 构建一
个你自己的集群,或者你可以使用下面任意一个 Kubernetes 工具构建:
要获知版本信息,请输入
kubectl version.
调试 Pod 调试一个 pod 的第一步是观察它。使用下面的命令检查 Pod 的当前状态和最近事件:
kubectl describe pods ${ POD_NAME }
看看 Pod 中的容器的状态。它们都是 Running 吗?最近有重启吗?
根据 Pod 的状态继续调试。
我的 Pod 停滞在 Pending 状态 如果 Pod 被卡在 Pending 状态,就意味着它不能调度在某个节点上。一般来说,这是因为某种类型的资源不足而
导致无法调度。 查看上面的命令 kubectl describe ... 的输出。调度器的消息中应该会包含无法调度 Pod 的原因。
原因包括:
资源不足 你可能已经耗尽了集群中供应的 CPU 或内存。在这个情况下你可以尝试几件事情:
向集群中添加节点。
终止不需要的 Pod
为 Pending 状态的 Pod 提供空间。
检查该 Pod 是否不大于你的节点。例如,如果全部节点具有 cpu:1 容量,那么具有
请求为 cpu: 1.1 的 Pod 永远不会被调度。
你可以使用 kubectl get nodes -o <format> 命令来检查节点容量。
下面是一些能够提取必要信息的命令示例:
kubectl get nodes -o yaml | egrep '\sname:|cpu:|memory:'
kubectl get nodes -o json | jq '.items[] | {name: .metadata.name, cap: .status.capacity}'
可以考虑配置资源配额 来限制可耗用的资源总量。
如果与命名空间一起使用,它可以防止一个团队吞噬所有的资源。
使用hostPort 当你将一个 Pod 绑定到某 hostPort 时,这个 Pod 能被调度的位置数量有限。
在大多数情况下,hostPort 是不必要的; 尝试使用服务对象来暴露你的 Pod。
如果你需要 hostPort,那么你可以调度的 Pod 数量不能超过集群的节点个数。
我的 Pod 一直在 Waiting 如果 Pod 一直停滞在 Waiting 状态,那么它已被调度在某个工作节点,但它不能在该机器上运行。
再次,来自 kubectl describe ... 的内容应该是可以是很有用的。
最常见的原因 Waiting 的 Pod 是无法拉取镜像。有三件事要检查:
确保你的镜像的名称正确。 你是否将镜像推送到存储库? 在你的机器上手动运行 docker pull <image>,看看是否可以拉取镜像。 我的 Pod 一直 Crashing 或者其他不健康状态 一旦 Pod 已经被调度,就可以依据
调试运行中的 Pod
展开进一步的调试工作。
调试 Replication Controller Replication Controller 相当简单。它们或者能或者不能创建 Pod。如果它们无法创建 Pod,
请参考上面的说明 来调试你的 Pod。
你也可以使用 kubectl describe rc ${CONTROLLER_NAME} 来检查和副本控制器有关的事件。
4.10.13 - 调试 Service 对于新安装的 Kubernetes,经常出现的问题是 Service 无法正常运行。 你已经通过
Deployment(或其他工作负载控制器)运行了 Pod,并创建 Service ,但是
当你尝试访问它时,没有任何响应。此文档有望对你有所帮助并找出问题所在。
在 Pod 中运行命令 对于这里的许多步骤,你可能希望知道运行在集群中的 Pod 看起来是什么样的。
最简单的方法是运行一个交互式的 alpine Pod:
$ kubectl run -it --rm --restart=Never alpine --image=alpine sh
说明: 如果没有看到命令提示符,请按回车。
如果你已经有了你想使用的正在运行的 Pod,则可以运行以下命令去进入:
kubectl exec <POD-NAME> -c <CONTAINER-NAME> -- <COMMAND>
设置 为了完成本次实践的任务,我们先运行几个 Pod。
由于你可能正在调试自己的 Service,所以,你可以使用自己的信息进行替换,
或者你也可以跟着教程并开始下面的步骤来获得第二个数据点。
kubectl create deployment hostnames --image= k8s.gcr.io/serve_hostname
deployment.apps/hostnames created
kubectl 命令将打印创建或变更的资源的类型和名称,它们可以在后续命令中使用。
让我们将这个 deployment 的副本数扩至 3。
kubectl scale deployment hostnames --replicas= 3
deployment.apps/hostnames scaled
请注意这与你使用以下 YAML 方式启动 Deployment 类似:
apiVersion : apps/v1
kind : Deployment
metadata :
labels :
app : hostnames
name : hostnames
spec :
selector :
matchLabels :
app : hostnames
replicas : 3
template :
metadata :
labels :
app : hostnames
spec :
containers :
- name : hostnames
image : k8s.gcr.io/serve_hostname
"app" 标签是 kubectl create deployment 根据 Deployment 名称自动设置的。
确认你的 Pods 是运行状态:
kubectl get pods -l app = hostnames
NAME READY STATUS RESTARTS AGE
hostnames-632524106-bbpiw 1/1 Running 0 2m
hostnames-632524106-ly40y 1/1 Running 0 2m
hostnames-632524106-tlaok 1/1 Running 0 2m
你还可以确认你的 Pod 是否正在提供服务。你可以获取 Pod IP 地址列表并直接对其进行测试。
kubectl get pods -l app = hostnames \
-o go-template= '{{range .items}}{{.status.podIP}}{{"\n"}}{{end}}'
10.244.0.5
10.244.0.6
10.244.0.7
用于本教程的示例容器仅通过 HTTP 在端口 9376 上提供其自己的主机名,
但是如果要调试自己的应用程序,则需要使用你的 Pod 正在侦听的端口号。
在 Pod 内运行:
for ep in 10.244.0.5:9376 10.244.0.6:9376 10.244.0.7:9376; do
wget -qO- $ep
done
输出类似这样:
hostnames-632524106-bbpiw
hostnames-632524106-ly40y
hostnames-632524106-tlaok
如果此时你没有收到期望的响应,则你的 Pod 状态可能不健康,或者可能没有在你认为正确的端口上进行监听。
你可能会发现 kubectl logs 命令对于查看正在发生的事情很有用,
或者你可能需要通过kubectl exec 直接进入 Pod 中并从那里进行调试。
假设到目前为止一切都已按计划进行,那么你可以开始调查为何你的 Service 无法正常工作。
Service 是否存在? 细心的读者会注意到我们实际上尚未创建 Service -这是有意而为之。 这一步有时会被遗忘,这是首先要检查的步骤。
那么,如果我尝试访问不存在的 Service 会怎样? 假设你有另一个 Pod 通过名称匹配到 Service ,你将得到类似结果:
Resolving hostnames (hostnames)... failed: Name or service not known.
wget: unable to resolve host address 'hostnames'
首先要检查的是该 Service 是否真实存在:
kubectl get svc hostnames
No resources found.
Error from server (NotFound): services "hostnames" not found
让我们创建 Service。 和以前一样,在这次实践中 - 你可以在此处使用自己的 Service 的内容。
kubectl expose deployment hostnames --port= 80 --target-port= 9376
service/hostnames exposed
重新运行查询命令,确认没有问题:
kubectl get svc hostnames
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
hostnames ClusterIP 10.0.1.175 <none> 80/TCP 5s
现在你知道了 Service 确实存在。
同前,此步骤效果与通过 YAML 方式启动 'Service' 一样:
apiVersion : v1
kind : Service
metadata :
name : hostnames
spec :
selector :
app : hostnames
ports :
- name : default
protocol : TCP
port : 80
targetPort : 9376
为了突出配置范围的完整性,你在此处创建的 Service 使用的端口号与 Pods 不同。
对于许多真实的 Service,这些值可以是相同的。
Service 是否可通过 DNS 名字访问? 通常客户端通过 DNS 名称来匹配到 Service。
从相同命名空间下的 Pod 中运行以下命令:
Address 1: 10.0.0.10 kube-dns.kube-system.svc.cluster.local
Name: hostnames
Address 1: 10.0.1.175 hostnames.default.svc.cluster.local
如果失败,那么你的 Pod 和 Service 可能位于不同的命名空间中,
请尝试使用限定命名空间的名称(同样在 Pod 内运行):
nslookup hostnames.default
Address 1: 10.0.0.10 kube-dns.kube-system.svc.cluster.local
Name: hostnames.default
Address 1: 10.0.1.175 hostnames.default.svc.cluster.local
如果成功,那么需要调整你的应用,使用跨命名空间的名称去访问它,
或者在相同的命名空间中运行应用和 Service。如果仍然失败,请尝试一个完全限定的名称:
nslookup hostnames.default.svc.cluster.local
Address 1: 10.0.0.10 kube-dns.kube-system.svc.cluster.local
Name: hostnames.default.svc.cluster.local
Address 1: 10.0.1.175 hostnames.default.svc.cluster.local
注意这里的后缀:"default.svc.cluster.local"。"default" 是我们正在操作的命名空间。
"svc" 表示这是一个 Service。"cluster.local" 是你的集群域,在你自己的集群中可能会有所不同。
你也可以在集群中的节点上尝试此操作:
说明: 10.0.0.10 是集群的 DNS 服务 IP,你的可能有所不同。
nslookup hostnames.default.svc.cluster.local 10.0.0.10
Server: 10.0.0.10
Address: 10.0.0.10#53
Name: hostnames.default.svc.cluster.local
Address: 10.0.1.175
如果你能够使用完全限定的名称查找,但不能使用相对名称,则需要检查你 Pod 中的
/etc/resolv.conf 文件是否正确。在 Pod 中运行以下命令:
你应该可以看到类似这样的输出:
nameserver 10.0.0.10
search default.svc.cluster.local svc.cluster.local cluster.local example.com
options ndots:5
nameserver 行必须指示你的集群的 DNS Service,
它是通过 --cluster-dns 标志传递到 kubelet 的。
search 行必须包含一个适当的后缀,以便查找 Service 名称。
在本例中,它查找本地命名空间(default.svc.cluster.local)中的服务和
所有命名空间(svc.cluster.local)中的服务,最后在集群(cluster.local)中查找
服务的名称。根据你自己的安装情况,可能会有额外的记录(最多 6 条)。
集群后缀是通过 --cluster-domain 标志传递给 kubelet 的。
本文中,我们假定后缀是 “cluster.local”。
你的集群配置可能不同,这种情况下,你应该在上面的所有命令中更改它。
options 行必须设置足够高的 ndots,以便 DNS 客户端库考虑搜索路径。
在默认情况下,Kubernetes 将这个值设置为 5,这个值足够高,足以覆盖它生成的所有 DNS 名称。
是否存在 Service 能通过 DNS 名称访问? 如果上面的方式仍然失败,DNS 查找不到你需要的 Service ,你可以后退一步,
看看还有什么其它东西没有正常工作。
Kubernetes 主 Service 应该一直是工作的。在 Pod 中运行如下命令:
nslookup kubernetes.default
Server: 10.0.0.10
Address 1: 10.0.0.10 kube-dns.kube-system.svc.cluster.local
Name: kubernetes.default
Address 1: 10.0.0.1 kubernetes.default.svc.cluster.local
如果失败,你可能需要转到本文的 kube-proxy 节,
或者甚至回到文档的顶部重新开始,但不是调试你自己的 Service ,而是调试 DNS Service。
Service 能够通过 IP 访问么? 假设你已经确认 DNS 工作正常,那么接下来要测试的是你的 Service 能否通过它的 IP 正常访问。
从集群中的一个 Pod,尝试访问 Service 的 IP(从上面的 kubectl get 命令获取)。
for i in $( seq 1 3) ; do
wget -qO- 10.0.1.175:80
done
输出应该类似这样:
hostnames-632524106-bbpiw
hostnames-632524106-ly40y
hostnames-632524106-tlaok
如果 Service 状态是正常的,你应该得到正确的响应。如果没有,有很多可能出错的地方,请继续阅读。
Service 的配置是否正确? 这听起来可能很愚蠢,但你应该两次甚至三次检查你的 Service 配置是否正确,并且与你的 Pod 匹配。
查看你的 Service 配置并验证它:
kubectl get service hostnames -o json
{
"kind" : "Service" ,
"apiVersion" : "v1" ,
"metadata" : {
"name" : "hostnames" ,
"namespace" : "default" ,
"uid" : "428c8b6c-24bc-11e5-936d-42010af0a9bc" ,
"resourceVersion" : "347189" ,
"creationTimestamp" : "2015-07-07T15:24:29Z" ,
"labels" : {
"app" : "hostnames"
}
},
"spec" : {
"ports" : [
{
"name" : "default" ,
"protocol" : "TCP" ,
"port" : 80 ,
"targetPort" : 9376 ,
"nodePort" : 0
}
],
"selector" : {
"app" : "hostnames"
},
"clusterIP" : "10.0.1.175" ,
"type" : "ClusterIP" ,
"sessionAffinity" : "None"
},
"status" : {
"loadBalancer" : {}
}
}
你想要访问的 Service 端口是否在 spec.ports[] 中列出? targetPort 对你的 Pod 来说正确吗(许多 Pod 使用与 Service 不同的端口)?如果你想使用数值型端口,那么它的类型是一个数值(9376)还是字符串 “9376”? 如果你想使用名称型端口,那么你的 Pod 是否暴露了一个同名端口? 端口的 protocol 和 Pod 的是否对应? Service 有 Endpoints 吗? 如果你已经走到了这一步,你已经确认你的 Service 被正确定义,并能通过 DNS 解析。
现在,让我们检查一下,你运行的 Pod 确实是被 Service 选中的。
早些时候,我们已经看到 Pod 是运行状态。我们可以再检查一下:
kubectl get pods -l app = hostnames
NAME READY STATUS RESTARTS AGE
hostnames-632524106-bbpiw 1/1 Running 0 1h
hostnames-632524106-ly40y 1/1 Running 0 1h
hostnames-632524106-tlaok 1/1 Running 0 1h
-l app=hostnames 参数是一个标签选择算符 - 和我们 Service 中定义的一样。
"AGE" 列表明这些 Pod 已经启动一个小时了,这意味着它们运行良好,而未崩溃。
"RESTARTS" 列表明 Pod 没有经常崩溃或重启。经常性崩溃可能导致间歇性连接问题。
如果重启次数过大,通过调试 pod
了解相关技术。
在 Kubernetes 系统中有一个控制回路,它评估每个 Service 的选择算符,并将结果保存到 Endpoints 对象中。
kubectl get endpoints hostnames
NAME ENDPOINTS
hostnames 10.244.0.5:9376,10.244.0.6:9376,10.244.0.7:9376
这证实 Endpoints 控制器已经为你的 Service 找到了正确的 Pods。
如果 ENDPOINTS 列的值为 <none>,则应检查 Service 的 spec.selector 字段,
以及你实际想选择的 Pod 的 metadata.labels 的值。
常见的错误是输入错误或其他错误,例如 Service 想选择 app=hostnames,但是
Deployment 指定的是 run=hostnames。在 1.18之前的版本中 kubectl run
也可以被用来创建 Deployment。
Pod 正常工作吗? 至此,你知道你的 Service 已存在,并且已匹配到你的Pod。在本实验的开始,你已经检查了 Pod 本身。
让我们再次检查 Pod 是否确实在工作 - 你可以绕过 Service 机制并直接转到 Pod,如上面的 Endpoint 所示。
说明: 这些命令使用的是 Pod 端口(9376),而不是 Service 端口(80)。
在 Pod 中运行:
for ep in 10.244.0.5:9376 10.244.0.6:9376 10.244.0.7:9376; do
wget -qO- $ep
done
输出应该类似这样:
hostnames-632524106-bbpiw
hostnames-632524106-ly40y
hostnames-632524106-tlaok
你希望 Endpoint 列表中的每个 Pod 都返回自己的主机名。
如果情况并非如此(或你自己的 Pod 的正确行为是什么),你应调查发生了什么事情。
kube-proxy 正常工作吗? 如果你到达这里,则说明你的 Service 正在运行,拥有 Endpoints,Pod 真正在提供服务。
此时,整个 Service 代理机制是可疑的。让我们一步一步地确认它没问题。
Service 的默认实现(在大多数集群上应用的)是 kube-proxy。
这是一个在每个节点上运行的程序,负责配置用于提供 Service 抽象的机制之一。
如果你的集群不使用 kube-proxy,则以下各节将不适用,你将必须检查你正在使用的 Service 的实现方式。
kube-proxy 正常运行吗? 确认 kube-proxy 正在节点上运行。 在节点上直接运行,你将会得到类似以下的输出:
ps auxw | grep kube-proxy
root 4194 0.4 0.1 101864 17696 ? Sl Jul04 25:43 /usr/local/bin/kube-proxy --master=https://kubernetes-master --kubeconfig=/var/lib/kube-proxy/kubeconfig --v=2
下一步,确认它并没有出现明显的失败,比如连接主节点失败。要做到这一点,你必须查看日志。
访问日志的方式取决于你节点的操作系统。
在某些操作系统上日志是一个文件,如 /var/log/messages kube-proxy.log,
而其他操作系统使用 journalctl 访问日志。你应该看到输出类似于:
I1027 22:14:53.995134 5063 server.go:200] Running in resource-only container "/kube-proxy"
I1027 22:14:53.998163 5063 server.go:247] Using iptables Proxier.
I1027 22:14:53.999055 5063 server.go:255] Tearing down userspace rules. Errors here are acceptable.
I1027 22:14:54.038140 5063 proxier.go:352] Setting endpoints for "kube-system/kube-dns:dns-tcp" to [10.244.1.3:53]
I1027 22:14:54.038164 5063 proxier.go:352] Setting endpoints for "kube-system/kube-dns:dns" to [10.244.1.3:53]
I1027 22:14:54.038209 5063 proxier.go:352] Setting endpoints for "default/kubernetes:https" to [10.240.0.2:443]
I1027 22:14:54.038238 5063 proxier.go:429] Not syncing iptables until Services and Endpoints have been received from master
I1027 22:14:54.040048 5063 proxier.go:294] Adding new service "default/kubernetes:https" at 10.0.0.1:443/TCP
I1027 22:14:54.040154 5063 proxier.go:294] Adding new service "kube-system/kube-dns:dns" at 10.0.0.10:53/UDP
I1027 22:14:54.040223 5063 proxier.go:294] Adding new service "kube-system/kube-dns:dns-tcp" at 10.0.0.10:53/TCP
如果你看到有关无法连接主节点的错误消息,则应再次检查节点配置和安装步骤。
kube-proxy 无法正确运行的可能原因之一是找不到所需的 conntrack 二进制文件。
在一些 Linux 系统上,这也是可能发生的,这取决于你如何安装集群,
例如,你是手动开始一步步安装 Kubernetes。如果是这样的话,你需要手动安装
conntrack 包(例如,在 Ubuntu 上使用 sudo apt install conntrack),然后重试。
Kube-proxy 可以以若干模式之一运行。在上述日志中,Using iptables Proxier
行表示 kube-proxy 在 "iptables" 模式下运行。
最常见的另一种模式是 "ipvs"。先前的 "userspace" 模式已经被这些所代替。
Iptables 模式 在 "iptables" 模式中, 你应该可以在节点上看到如下输出:
iptables-save | grep hostnames
-A KUBE-SEP-57KPRZ3JQVENLNBR -s 10.244.3.6/32 -m comment --comment "default/hostnames:" -j MARK --set-xmark 0x00004000/0x00004000
-A KUBE-SEP-57KPRZ3JQVENLNBR -p tcp -m comment --comment "default/hostnames:" -m tcp -j DNAT --to-destination 10.244.3.6:9376
-A KUBE-SEP-WNBA2IHDGP2BOBGZ -s 10.244.1.7/32 -m comment --comment "default/hostnames:" -j MARK --set-xmark 0x00004000/0x00004000
-A KUBE-SEP-WNBA2IHDGP2BOBGZ -p tcp -m comment --comment "default/hostnames:" -m tcp -j DNAT --to-destination 10.244.1.7:9376
-A KUBE-SEP-X3P2623AGDH6CDF3 -s 10.244.2.3/32 -m comment --comment "default/hostnames:" -j MARK --set-xmark 0x00004000/0x00004000
-A KUBE-SEP-X3P2623AGDH6CDF3 -p tcp -m comment --comment "default/hostnames:" -m tcp -j DNAT --to-destination 10.244.2.3:9376
-A KUBE-SERVICES -d 10.0.1.175/32 -p tcp -m comment --comment "default/hostnames: cluster IP" -m tcp --dport 80 -j KUBE-SVC-NWV5X2332I4OT4T3
-A KUBE-SVC-NWV5X2332I4OT4T3 -m comment --comment "default/hostnames:" -m statistic --mode random --probability 0.33332999982 -j KUBE-SEP-WNBA2IHDGP2BOBGZ
-A KUBE-SVC-NWV5X2332I4OT4T3 -m comment --comment "default/hostnames:" -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-X3P2623AGDH6CDF3
-A KUBE-SVC-NWV5X2332I4OT4T3 -m comment --comment "default/hostnames:" -j KUBE-SEP-57KPRZ3JQVENLNBR
对于每个 Service 的每个端口,应有 1 条 KUBE-SERVICES 规则、一个 KUBE-SVC-<hash> 链。
对于每个 Pod 末端,在那个 KUBE-SVC-<hash> 链中应该有一些规则与之对应,还应该
有一个 KUBE-SEP-<hash> 链与之对应,其中包含为数不多的几条规则。
实际的规则数量可能会根据你实际的配置(包括 NodePort 和 LoadBalancer 服务)有所不同。
IPVS 模式 在 "ipvs" 模式中, 你应该在节点下看到如下输出:
Prot LocalAddress:Port Scheduler Flags
-> RemoteAddress:Port Forward Weight ActiveConn InActConn
...
TCP 10.0.1.175:80 rr
-> 10.244.0.5:9376 Masq 1 0 0
-> 10.244.0.6:9376 Masq 1 0 0
-> 10.244.0.7:9376 Masq 1 0 0
...
对于每个 Service 的每个端口,还有 NodePort,External IP 和 LoadBalancer 类型服务
的 IP,kube-proxy 将创建一个虚拟服务器。
对于每个 Pod 末端,它将创建相应的真实服务器。
在此示例中,服务主机名(10.0.1.175:80)拥有 3 个末端(10.244.0.5:9376、
10.244.0.6:9376 和 10.244.0.7:9376)。
Userspace 模式 在极少数情况下,你可能会用到 "userspace" 模式。在你的节点上运行:
iptables-save | grep hostnames
-A KUBE-PORTALS-CONTAINER -d 10.0.1.175/32 -p tcp -m comment --comment "default/hostnames:default" -m tcp --dport 80 -j REDIRECT --to-ports 48577
-A KUBE-PORTALS-HOST -d 10.0.1.175/32 -p tcp -m comment --comment "default/hostnames:default" -m tcp --dport 80 -j DNAT --to-destination 10.240.115.247:48577
对于 Service (本例中只有一个)的每个端口,应当有 2 条规则:
一条 "KUBE-PORTALS-CONTAINER" 和一条 "KUBE-PORTALS-HOST" 规则。
几乎没有人应该再使用 "userspace" 模式,因此你在这里不会花更多的时间。
kube-proxy 是否在运行? 假设你确实遇到上述情况之一,请重试从节点上通过 IP 访问你的 Service :
hostnames-632524106-bbpiw
如果失败,并且你正在使用用户空间代理,则可以尝试直接访问代理。
如果你使用的是 iptables 代理,请跳过本节。
回顾上面的 iptables-save 输出,并提取 kube-proxy 为你的 Service 所使用的端口号。
在上面的例子中,端口号是 “48577”。现在试着连接它:
hostnames-632524106-tlaok
如果这步操作仍然失败,请查看 kube-proxy 日志中的特定行,如:
Setting endpoints for default/hostnames:default to [10.244.0.5:9376 10.244.0.6:9376 10.244.0.7:9376]
如果你没有看到这些,请尝试将 -V 标志设置为 4 并重新启动 kube-proxy,然后再查看日志。
边缘案例: Pod 无法通过 Service IP 连接到它本身 这听起来似乎不太可能,但是确实可能发生,并且应该可行。
如果网络没有为“发夹模式(Hairpin)”流量生成正确配置,
通常当 kube-proxy 以 iptables 模式运行,并且 Pod 与桥接网络连接时,就会发生这种情况。
kubelet 提供了 hairpin-mode
标志 。
如果 Service 的末端尝试访问自己的 Service VIP,则该端点可以把流量负载均衡回来到它们自身。
hairpin-mode 标志必须被设置为 hairpin-veth 或者 promiscuous-bridge。
诊断此类问题的常见步骤如下:
确认 hairpin-mode 被设置为 hairpin-veth 或 promiscuous-bridge。
你应该可以看到下面这样。本例中 hairpin-mode 被设置为 promiscuous-bridge。
root 3392 1.1 0.8 186804 65208 ? Sl 00:51 11:11 /usr/local/bin/kubelet --enable-debugging-handlers=true --config=/etc/kubernetes/manifests --allow-privileged=True --v=4 --cluster-dns=10.0.0.10 --cluster-domain=cluster.local --configure-cbr0=true --cgroup-root=/ --system-cgroups=/system --hairpin-mode=promiscuous-bridge --runtime-cgroups=/docker-daemon --kubelet-cgroups=/kubelet --babysit-daemons=true --max-pods=110 --serialize-image-pulls=false --outofdisk-transition-frequency=0
确认有效的 hairpin-mode。要做到这一点,你必须查看 kubelet 日志。
访问日志取决于节点的操作系统。在一些操作系统上,它是一个文件,如 /var/log/kubelet.log,
而其他操作系统则使用 journalctl 访问日志。请注意,由于兼容性,
有效的 hairpin-mode 可能不匹配 --hairpin-mode 标志。在 kubelet.log
中检查是否有带有关键字 hairpin 的日志行。应该有日志行指示有效的
hairpin-mode,就像下面这样。
I0629 00:51:43.648698 3252 kubelet.go:380] Hairpin mode set to "promiscuous-bridge"
如果有效的发卡模式是 promiscuous-bridge, 要保证 Kubelet 有操作节点上
Linux 网桥的权限。如果 cbr0 桥正在被使用且被正确设置,你将会看到如下输出:
ifconfig cbr0 |grep PROMISC
UP BROADCAST RUNNING PROMISC MULTICAST MTU:1460 Metric:1
寻求帮助 如果你走到这一步,那么就真的是奇怪的事情发生了。你的 Service 正在运行,有 Endpoints 存在,
你的 Pods 也确实在提供服务。你的 DNS 正常,iptables 规则已经安装,kube-proxy 看起来也正常。
然而 Service 还是没有正常工作。这种情况下,请告诉我们,以便我们可以帮助调查!
通过
Slack 或者
Forum 或者
GitHub
联系我们。
接下来 访问故障排查文档 获取更多信息。
4.10.14 - 调试StatefulSet 此任务展示如何调试 StatefulSet。
准备开始 你需要有一个 Kubernetes 集群,已配置好的 kubectl 命令行工具与你的集群进行通信。 你应该有一个运行中的 StatefulSet,以便用于调试。 调试 StatefulSet StatefulSet 在创建 Pod 时为其设置了 app=myapp 标签,列出仅属于某 StatefulSet
的所有 Pod 时,可以使用以下命令:
kubectl get pods -l app = myapp
如果你发现列出的任何 Pod 长时间处于 Unknown 或 Terminating 状态,请参阅
删除 StatefulSet Pods
了解如何处理它们的说明。
你可以参考调试 Pods
来调试 StatefulSet 中的各个 Pod。
接下来 4.10.15 - 调试运行中的 Pod 本页解释如何在节点上调试运行中(或崩溃)的 Pod。
准备开始 检查 Pod 的日志 首先,查看受到影响的容器的日志:
kubectl logs ${ POD_NAME } ${ CONTAINER_NAME }
如果你的容器之前崩溃过,你可以通过下面命令访问之前容器的崩溃日志:
kubectl logs --previous ${ POD_NAME } ${ CONTAINER_NAME }
使用容器 exec 进行调试 如果 容器镜像 包含调试程序,
比如从 Linux 和 Windows 操作系统基础镜像构建的镜像,你可以使用 kubectl exec 命令
在特定的容器中运行一些命令:
kubectl exec ${ POD_NAME } -c ${ CONTAINER_NAME } -- ${ CMD } ${ ARG1 } ${ ARG2 } ... ${ ARGN }
说明: -c ${CONTAINER_NAME} 是可选择的。如果Pod中仅包含一个容器,就可以忽略它。
例如,要查看正在运行的 Cassandra pod中的日志,可以运行:
kubectl exec cassandra -- cat /var/log/cassandra/system.log
你可以在 kubectl exec 命令后面加上 -i 和 -t 来运行一个连接到你的终端的 Shell,比如:
kubectl exec -it cassandra -- sh
若要了解更多内容,可查看获取正在运行容器的 Shell 。
使用临时调试容器来进行调试 FEATURE STATE: Kubernetes v1.18 [alpha]
当由于容器崩溃或容器镜像不包含调试程序(例如无发行版镜像 等)
而导致 kubectl exec 无法运行时,临时容器 对于排除交互式故障很有用。
从 'v1.18' 版本开始,'kubectl' 有一个可以创建用于调试的临时容器的 alpha 命令。
使用临时容器来调试的例子 说明: 本示例需要你的集群已经开启
EphemeralContainers
特性门控 ,
kubectl 版本为 v1.18 或者更高。
你可以使用 kubectl alpha debug 命令来给正在运行中的 Pod 增加一个临时容器。
首先,像示例一样创建一个 pod:
kubectl run ephemeral-demo --image= k8s.gcr.io/pause:3.1 --restart= Never
说明: 本节示例中使用 pause 容器镜像,因为它不包含任何用户级调试程序,但是这个方法适用于所有容器镜像。
如果你尝试使用 kubectl exec 来创建一个 shell,你将会看到一个错误,因为这个容器镜像中没有 shell。
kubectl exec -it ephemeral-demo -- sh
OCI runtime exec failed: exec failed: container_linux.go:346: starting container process caused "exec: \"sh\": executable file not found in $PATH": unknown
你可以改为使用 kubectl alpha debug 添加调试容器。
如果你指定 -i 或者 --interactive 参数,kubectl 将自动挂接到临时容器的控制台。
kubectl alpha debug -it ephemeral-demo --image= busybox --target= ephemeral-demo
Defaulting debug container name to debugger-8xzrl.
If you don't see a command prompt, try pressing enter.
/ #
此命令添加一个新的 busybox 容器并将其挂接到该容器。--target 参数指定另一个容器的进程命名空间。
这是必需的,因为 kubectl run 不能在它创建的pod中启用
共享进程命名空间 。
说明: 容器运行时 必须支持
--target参数。
如果不支持,则临时容器可能不会启动,或者可能使用隔离的进程命名空间启动。
你可以使用 kubectl describe 查看新创建的临时容器的状态:
kubectl describe pod ephemeral-demo
...
Ephemeral Containers:
debugger-8xzrl:
Container ID: docker://b888f9adfd15bd5739fefaa39e1df4dd3c617b9902082b1cfdc29c4028ffb2eb
Image: busybox
Image ID: docker-pullable://busybox@sha256:1828edd60c5efd34b2bf5dd3282ec0cc04d47b2ff9caa0b6d4f07a21d1c08084
Port: <none>
Host Port: <none>
State: Running
Started: Wed, 12 Feb 2020 14:25:42 +0100
Ready: False
Restart Count: 0
Environment: <none>
Mounts: <none>
...
使用 kubectl delete 来移除已经结束掉的 Pod:
kubectl delete pod ephemeral-demo
通过 Pod 副本调试 有些时候 Pod 的配置参数使得在某些情况下很难执行故障排查。
例如,在容器镜像中不包含 shell 或者你的应用程序在启动时崩溃的情况下,
就不能通过运行 kubectl exec 来排查容器故障。
在这些情况下,你可以使用 kubectl debug 来创建 Pod 的副本,通过更改配置帮助调试。
在添加新的容器时创建 Pod 副本 当应用程序正在运行但其表现不符合预期时,你会希望在 Pod 中添加额外的调试工具,
这时添加新容器是很有用的。
例如,应用的容器镜像是建立在 busybox 的基础上,
但是你需要 busybox 中并不包含的调试工具。
你可以使用 kubectl run 模拟这个场景:
kubectl run myapp --image= busybox --restart= Never -- sleep 1d
通过运行以下命令,建立 myapp 的一个名为 myapp-debug 的副本,
新增了一个用于调试的 Ubuntu 容器,
kubectl debug myapp -it --image= ubuntu --share-processes --copy-to= myapp-debug
Defaulting debug container name to debugger-w7xmf.
If you don't see a command prompt, try pressing enter.
root@myapp-debug:/#
说明: 如果你没有使用 --container 指定新的容器名,kubectl debug 会自动生成的。 默认情况下,-i 标志使 kubectl debug 附加到新容器上。
你可以通过指定 --attach=false 来防止这种情况。
如果你的会话断开连接,你可以使用 kubectl attach 重新连接。 --share-processes 允许在此 Pod 中的其他容器中查看该容器的进程。
参阅在 Pod 中的容器之间共享进程命名空间
获取更多信息。不要忘了清理调试 Pod:
kubectl delete pod myapp myapp-debug
在改变 Pod 命令时创建 Pod 副本 有时更改容器的命令很有用,例如添加调试标志或因为应用崩溃。
为了模拟应用崩溃的场景,使用 kubectl run 命令创建一个立即退出的容器:
kubectl run --image=busybox myapp -- false
使用 kubectl describe pod myapp 命令,你可以看到容器崩溃了:
Containers:
myapp:
Image: busybox
...
Args:
false
State: Waiting
Reason: CrashLoopBackOff
Last State: Terminated
Reason: Error
Exit Code: 1
你可以使用 kubectl debug 命令创建该 Pod 的一个副本,
在该副本中命令改变为交互式 shell:
kubectl debug myapp -it --copy-to=myapp-debug --container=myapp -- sh
If you don't see a command prompt, try pressing enter.
/ #
现在你有了一个可以执行类似检查文件系统路径或者手动运行容器命令的交互式 shell。
说明: 要更改指定容器的命令,你必须用 --container 命令指定容器的名字,
否则 kubectl debug 将建立一个新的容器运行你指定的命令。 默认情况下,标志 -i 使 kubectl debug 附加到容器。
你可通过指定 --attach=false 来防止这种情况。
如果你的断开连接,可以使用 kubectl attach 重新连接。 不要忘了清理调试 Pod:
kubectl delete pod myapp myapp-debug
在更改容器镜像时创建 Pod 副本 在某些情况下,你可能想从正常生产容器镜像中
把行为异常的 Pod 改变为包含调试版本或者附加应用的镜像。
下面的例子,用 kubectl run创建一个 Pod:
kubectl run myapp --image=busybox --restart=Never -- sleep 1d
现在可以使用 kubectl debug 创建一个副本
并改变容器镜像为 ubuntu:
kubectl debug myapp --copy-to=myapp-debug --set-image=*=ubuntu
--set-image 与 container_name=image 使用相同的 kubectl set image 语法。
*=ubuntu 表示把所有容器的镜像改为 ubuntu。
kubectl delete pod myapp myapp-debug
在节点上通过 shell 来调试 如果这些方法都不起作用,你可以找到运行 Pod 的主机并通过 SSH 进入该主机,
但是如果使用 Kubernetes API 中的工具,则通常不需要这样做。
因此,如果你发现自己需要使用 ssh 进入主机,请在GitHub 上提交功能请求,
以描述你的用例以及这些工具不足的原因。
4.10.16 - 资源指标管道 资源使用指标,例如容器 CPU 和内存使用率,可通过 Metrics API 在 Kubernetes 中获得。
这些指标可以直接被用户访问,比如使用 kubectl top 命令行,或者被集群中的控制器
(例如 Horizontal Pod Autoscalers) 使用来做决策。
Metrics API 通过 Metrics API,你可以获得指定节点或 Pod 当前使用的资源量。
此 API 不存储指标值,因此想要获取某个指定节点 10 分钟前的
资源使用量是不可能的。
此 API 与其他 API 没有区别:
此 API 和其它 Kubernetes API 一起位于同一端点(endpoint)之下且可发现,
路径为 /apis/metrics.k8s.io/ 它具有相同的安全性、可扩展性和可靠性保证 Metrics API 在 k8s.io/metrics
仓库中定义。你可以在那里找到有关 Metrics API 的更多信息。
说明: Metrics API 需要在集群中部署 Metrics Server。否则它将不可用。
度量资源用量 CPU CPU 用量按其一段时间内的平均值统计,单位为
CPU 核 。
此度量值通过在内核(包括 Linux 和 Windows)提供的累积 CPU 计数器乘以一个系数得到。
kubelet 组件负责选择计算系数所使用的窗口大小。
内存 内存用量按工作集(Working Set)的大小字节数统计,其数值为收集度量值的那一刻的内存用量。
如果一切都很理想化,“工作集” 是任务在使用的内存总量,该内存是不可以在内存压力较大
的情况下被释放的。
不过,具体的工作集计算方式取决于宿主 OS,有很大不同,且通常都大量使用启发式
规则来给出一个估计值。
其中包含所有匿名内存使用(没有后台文件提供存储者),因为 Kubernetes 不支持交换分区。
度量值通常包含一些高速缓存(有后台文件提供存储)内存,因为宿主操作系统并不是总能
回收这些页面。
Metrics 服务器 Metrics 服务器
是集群范围资源用量数据的聚合器。
默认情况下,在由 kube-up.sh 脚本创建的集群中会以 Deployment 的形式被部署。
如果你使用其他 Kubernetes 安装方法,则可以使用提供的
部署组件 components.yaml
来部署。
Metric 服务器从每个节点上的 kubelet
公开的 Summary API 中采集指标信息。
该 API 通过
Kubernetes 聚合器
注册到主 API 服务器上。
在设计文档
中可以了解到有关 Metrics 服务器的更多信息。
4.10.17 - 资源监控工具 要扩展应用程序并提供可靠的服务,你需要了解应用程序在部署时的行为。
你可以通过检测容器检查 Kubernetes 集群中的应用程序性能,
Pods ,
服务
和整个集群的特征。
Kubernetes 在每个级别上提供有关应用程序资源使用情况的详细信息。
此信息使你可以评估应用程序的性能,以及在何处可以消除瓶颈以提高整体性能。
在 Kubernetes 中,应用程序监控不依赖单个监控解决方案。
在新集群上,你可以使用资源度量 或
完整度量 管道来收集监视统计信息。
资源度量管道 资源指标管道提供了一组与集群组件,例如
Horizontal Pod Autoscaler
控制器以及 kubectl top 实用程序相关的有限度量。
这些指标是由轻量级的、短期、内存存储的
metrics-server 收集的,
通过 metrics.k8s.io 公开。
度量服务器发现集群中的所有节点,并且查询每个节点的
kubelet
以获取 CPU 和内存使用情况。
Kubelet 充当 Kubernetes 主节点与节点之间的桥梁,管理机器上运行的 Pod 和容器。
kubelet 将每个 Pod 转换为其组成的容器,并在容器运行时通过容器运行时接口
获取各个容器使用情况统计信息。
kubelet 从集成的 cAdvisor 获取此信息,以进行旧式 Docker 集成。
然后,它通过 metrics-server Resource Metrics API 公开聚合的 pod 资源使用情况统计信息。
该 API 在 kubelet 的经过身份验证和只读的端口上的 /metrics/resource/v1beta1 中提供。
完整度量管道 一个完整度量管道可以让你访问更丰富的度量。
Kubernetes 还可以根据集群的当前状态,使用 Pod 水平自动扩缩器等机制,
通过自动调用扩展或调整集群来响应这些度量。
监控管道从 kubelet 获取度量值,然后通过适配器将它们公开给 Kubernetes,
方法是实现 custom.metrics.k8s.io 或 external.metrics.k8s.io API。
Prometheus 是一个 CNCF 项目,可以原生监控 Kubernetes、
节点和 Prometheus 本身。
完整度量管道项目不属于 CNCF 的一部分,不在 Kubernetes 文档的范围之内。
4.10.18 - 集群故障排查 本篇文档是介绍集群故障排查的;我们假设对于你碰到的问题,你已经排除了是由应用程序造成的。
对于应用的调试,请参阅
应用故障排查指南 。
你也可以访问故障排查
来获取更多的信息。
列举集群节点 调试的第一步是查看所有的节点是否都已正确注册。
运行
验证你所希望看见的所有节点都能够显示出来,并且都处于 Ready 状态。
为了了解你的集群的总体健康状况详情,你可以运行:
kubectl cluster-info dump
查看日志 到这里,挖掘出集群更深层的信息就需要登录到相关的机器上。下面是相关日志文件所在的位置。
(注意,对于基于 systemd 的系统,你可能需要使用journalctl)。
主控节点 /var/log/kube-apiserver.log - API 服务器, 提供API服务/var/log/kube-scheduler.log - 调度器, 负责产生调度决策/var/log/kube-controller-manager.log - 管理副本控制器的控制器工作节点 /var/log/kubelet.log - kubelet,负责在节点运行容器/var/log/kube-proxy.log - kube-proxy, 负责服务的负载均衡集群故障模式的一般性概述 下面是一个不完整的列表,列举了一些可能的出错场景,以及通过调整集群配置来解决相关问题的方法。
根本原因 VM(s) 关机 集群之间,或者集群和用户之间网络分裂 Kubernetes 软件本身崩溃 数据丢失或者持久化存储不可用(如:GCE PD 或 AWS EBS 卷) 操作错误,如:Kubernetes 或者应用程序配置错误 具体情况: API 服务器所在的 VM 关机或者 API 服务器崩溃结果不能停止、更新或者启动新的 Pod、服务或副本控制器 现有的 Pod 和服务在不依赖 Kubernetes API 的情况下应该能继续正常工作 API 服务器的后端存储丢失结果API 服务器应该不能启动 kubelet 将不能访问 API 服务器,但是能够继续运行之前的 Pod 和提供相同的服务代理 在 API 服务器重启之前,需要手动恢复或者重建 API 服务器的状态 Kubernetes 服务组件(节点控制器、副本控制器管理器、调度器等)所在的 VM 关机或者崩溃当前,这些控制器是和 API 服务器在一起运行的,它们不可用的现象是与 API 服务器类似的 将来,这些控制器也会复制为多份,并且可能不在运行于同一节点上 它们没有自己的持久状态 单个节点(VM 或者物理机)关机 网络分裂结果分区 A 认为分区 B 中所有的节点都已宕机;分区 B 认为 API 服务器宕机
(假定主控节点所在的 VM 位于分区 A 内)。 kubelet 软件故障结果崩溃的 kubelet 就不能在其所在的节点上启动新的 Pod kubelet 可能删掉 Pod 或者不删 节点被标识为非健康态 副本控制器会在其它的节点上启动新的 Pod 集群操作错误结果丢失 Pod 或服务等等 丢失 API 服务器的后端存储 用户无法读取API 等等 缓解措施: 4.11 - 扩展 Kubernetes 了解针对工作环境需要来调整 Kubernetes 集群的进阶方法。
4.11.1 - 使用自定义资源 4.11.1.1 - 使用 CustomResourceDefinition 扩展 Kubernetes API 本页展示如何使用
CustomResourceDefinition
将
定制资源(Custom Resource)
安装到 Kubernetes API 上。
准备开始
你必须拥有一个 Kubernetes 的集群,同时你的 Kubernetes 集群必须带有 kubectl 命令行工具。
如果你还没有集群,你可以通过 Minikube 构建一
个你自己的集群,或者你可以使用下面任意一个 Kubernetes 工具构建:
您的 Kubernetes 服务器版本必须不低于版本 1.16.
要获知版本信息,请输入
kubectl version.
如果你在使用较老的、仍处于被支持范围的 Kubernetes 版本,请切换到该版本的
文档查看对于的集群而言有用的建议。
创建 CustomResourceDefinition 当你创建新的 CustomResourceDefinition(CRD)时,Kubernetes API 服务器会为你所
指定的每一个版本生成一个 RESTful 的 资源路径。CRD 可以是名字空间作用域的,也可以
是集群作用域的,取决于 CRD 的 scope 字段设置。和其他现有的内置对象一样,删除
一个名字空间时,该名字空间下的所有定制对象也会被删除。CustomResourceDefinition
本身是不受名字空间限制的,对所有名字空间可用。
例如,如果你将下面的 CustomResourceDefinition 保存到 resourcedefinition.yaml
文件:
apiVersion : apiextensions.k8s.io/v1
kind : CustomResourceDefinition
metadata :
# 名字必需与下面的 spec 字段匹配,并且格式为 '<名称的复数形式>.<组名>'
name : crontabs.stable.example.com
spec :
# 组名称,用于 REST API: /apis/<组>/<版本>
group : stable.example.com
# 列举此 CustomResourceDefinition 所支持的版本
versions :
- name : v1
# 每个版本都可以通过 served 标志来独立启用或禁止
served : true
# 其中一个且只有一个版本必需被标记为存储版本
storage : true
schema :
openAPIV3Schema :
type : object
properties :
spec :
type : object
properties :
cronSpec :
type : string
image :
type : string
replicas :
type : integer
# 可以是 Namespaced 或 Cluster
scope : Namespaced
names :
# 名称的复数形式,用于 URL:/apis/<组>/<版本>/<名称的复数形式>
plural : crontabs
# 名称的单数形式,作为命令行使用时和显示时的别名
singular : crontab
# kind 通常是单数形式的驼峰编码(CamelCased)形式。你的资源清单会使用这一形式。
kind : CronTab
# shortNames 允许你在命令行使用较短的字符串来匹配资源
shortNames :
- ct
之后创建它:
kubectl apply -f resourcedefinition.yaml
这样一个新的受名字空间约束的 RESTful API 端点会被创建在:
/apis/stable.example.com/v1/namespaces/*/crontabs/...
此端点 URL 自此可以用来创建和管理定制对象。对象的 kind 将是来自你上面创建时
所用的 spec 中指定的 CronTab。
创建端点的操作可能需要几秒钟。你可以监测你的 CustomResourceDefinition 的
Established 状况变为 true,或者监测 API 服务器的发现信息等待你的资源出现在
那里。
创建定制对象 在创建了 CustomResourceDefinition 对象之后,你可以创建定制对象(Custom
Objects)。定制对象可以包含定制字段。这些字段可以包含任意的 JSON 数据。
在下面的例子中,在类别为 CrontTab 的定制对象中,设置了cronSpec 和 image
定制字段。类别 CronTab 来自你在上面所创建的 CRD 的规约。
如果你将下面的 YAML 保存到 my-crontab.yaml:
apiVersion : "stable.example.com/v1"
kind : CronTab
metadata :
name : my-new-cron-object
spec :
cronSpec : "* * * * */5"
image : my-awesome-cron-image
并执行创建命令:
kubectl apply -f my-crontab.yaml
你就可以使用 kubectl 来管理你的 CronTab 对象了。例如:
应该会输出如下列表:
NAME AGE
my-new-cron-object 6s
使用 kubectl 时,资源名称是大小写不敏感的,而且你既可以使用 CRD 中所定义的单数
形式或复数形式,也可以使用其短名称:
你可以看到输出中包含了你创建定制对象时在 YAML 文件中指定的定制字段 cronSpec
和 image:
apiVersion : v1
kind : List
items :
- apiVersion : stable.example.com/v1
kind : CronTab
metadata :
creationTimestamp : 2017-05-31T12:56:35Z
generation : 1
name : my-new-cron-object
namespace : default
resourceVersion : "285"
uid : 9423255b-4600-11e7-af6a-28d2447dc82b
spec :
cronSpec : '* * * * */5'
image : my-awesome-cron-image
metadata :
resourceVersion : ""
删除 CustomResourceDefinition 当你删除某 CustomResourceDefinition 时,服务器会卸载其 RESTful API
端点,并删除服务器上存储的所有定制对象。
kubectl delete -f resourcedefinition.yaml
kubectl get crontabs
Error from server (NotFound): Unable to list {"stable.example.com" "v1" "crontabs"}: the server could not find the requested resource (get crontabs.stable.example.com)
如果你在以后创建相同的 CustomResourceDefinition 时,该 CRD 会是一个空的结构。
设置结构化的模式 CustomResource 对象在定制字段中保存结构化的数据,这些字段和内置的字段
apiVersion、kind 和 metadata 等一起存储,不过内置的字段都会被 API
服务器隐式完成合法性检查。有了 OpenAPI v3.0 检查
能力之后,你可以设置一个模式(Schema),在创建和更新定制对象时,这一模式会被用来
对对象内容进行合法性检查。参阅下文了解这类模式的细节和局限性。
在 apiextensions.k8s.io/v1 版本中,CustomResourceDefinition 的这一结构化模式
定义是必需的。
在 CustomResourceDefinition 的 beta 版本中,结构化模式定义是可选的。
结构化模式本身是一个 OpenAPI v3.0 验证模式 ,其中:
为对象根(root)设置一个非空的 type 值(藉由 OpenAPI 中的 type),对每个
object 节点的每个字段(藉由 OpenAPI 中的 properties 或 additionalProperties)以及
array 节点的每个条目(藉由 OpenAPI 中的 items)也要设置非空的 type 值,
除非:节点包含属性 x-kubernetes-int-or-string: true 节点包含属性 x-kubernetes-preserve-unknown-fields: true 对于 object 的每个字段或 array 中的每个条目,如果其定义中包含 allOf、anyOf、oneOf
或 not,则模式也要指定这些逻辑组合之外的字段或条目(试比较例 1 和例 2)。 在 allOf、anyOf、oneOf 或 not 上下文内不设置 description、type、default、
additionalProperties 或者 nullable。此规则的例外是
x-kubernetes-int-or-string 的两种模式(见下文)。 如果 metadata 被设置,则只允许对 metadata.name 和 metadata.generateName 设置约束。 非结构化的例 1:
allOf :
- properties :
foo :
...
违反了第 2 条规则。下面的是正确的:
properties :
foo :
...
allOf :
- properties :
foo :
...
非结构化的例 2:
allOf :
- items :
properties :
foo :
...
违反了第 2 条规则。下面的是正确的:
items :
properties :
foo :
...
allOf :
- items :
properties :
foo :
...
非结构化的例 3:
properties :
foo :
pattern : "abc"
metadata :
type : object
properties :
name :
type : string
pattern : "^a"
finalizers :
type : array
items :
type : string
pattern : "my-finalizer"
anyOf :
- properties :
bar :
type : integer
minimum : 42
required : ["bar" ]
description : "foo bar object"
不是一个结构化的模式,因为其中存在以下违例:
根节点缺失 type 设置(规则 1) foo 的 type 缺失(规则 1)anyOf 中的 bar 未在外部指定(规则 2)bar 的 type 位于 anyOf 中(规则 3)anyOf 中设置了 description (规则 3)metadata.finalizers 不可以被限制 (规则 4)作为对比,下面的 YAML 所对应的模式则是结构化的:
type : object
description : "foo bar object"
properties :
foo :
type : string
pattern : "abc"
bar :
type : integer
metadata :
type : object
properties :
name :
type : string
pattern : "^a"
anyOf :
- properties :
bar :
minimum : 42
required : ["bar" ]
如果违反了结构化模式规则,CustomResourceDefinition 的 NonStructural 状况中
会包含报告信息。
字段剪裁 CustomResourceDefinition 在集群的持久性存储
etcd
中保存经过合法性检查的资源数据。
就像原生的 Kubernetes 资源,例如 ConfigMap ,
如果你指定了 API 服务器所无法识别的字段,则该未知字段会在保存资源之前
被 剪裁(Pruned) 掉(删除)。
说明: 从 apiextensions.k8s.io/v1beta1 转换到 apiextensions.k8s.io/v1 的 CRD
可能没有结构化的模式定义,因此其 spec.preserveUnknownFields 可能为 true。
对于使用 apiextensions.k8s.io/v1beta1 且将 spec.preserveUnknownFields 设置为 true
创建的旧 CustomResourceDefinition 对象,有以下表现:
为了与 apiextensions.k8s.io/v1 兼容,将你的自定义资源定义更新为:
使用结构化的 OpenAPI 模式。 spec.preserveUnknownFields 设置为 false。如果你将下面的 YAML 保存到 my-crontab.yaml 文件:
apiVersion : "stable.example.com/v1"
kind : CronTab
metadata :
name : my-new-cron-object
spec :
cronSpec : "* * * * */5"
image : my-awesome-cron-image
someRandomField : 42
并创建之:
kubectl create --validate= false -f my-crontab.yaml -o yaml
输出类似于:
apiVersion: stable.example.com/v1
kind: CronTab
metadata:
creationTimestamp: 2017-05-31T12:56:35Z
generation: 1
name: my-new-cron-object
namespace: default
resourceVersion: "285"
uid: 9423255b-4600-11e7-af6a-28d2447dc82b
spec:
cronSpec: '* * * * */5'
image: my-awesome-cron-image
注意其中的字段 someRandomField 已经被剪裁掉。
本例中通过 --validate=false 命令行选项 关闭了客户端的合法性检查以展示 API 服务器的行为,
因为 OpenAPI 合法性检查模式也会发布到
客户端,kubectl 也会检查未知的字段并在对象被发送到 API
服务器之前就拒绝它们。
控制剪裁 默认情况下,定制资源的所有版本中的所有未规定的字段都会被剪裁掉。
通过在结构化的 OpenAPI v3 检查模式定义
中为特定字段的子树添加 x-kubernetes-preserve-unknown-fields: true 属性,可以
选择不对其执行剪裁操作。
例如:
type : object
properties :
json :
x-kubernetes-preserve-unknown-fields : true
字段 json 可以保存任何 JSON 值,其中内容不会被剪裁掉。
你也可以部分地指定允许的 JSON 数据格式;例如:
type : object
properties :
json :
x-kubernetes-preserve-unknown-fields : true
type : object
description : this is arbitrary JSON
通过这样设置,JSON 中只能设置 object 类型的值。
对于所指定的每个属性(或 additionalProperties),剪裁会再次被启用。
type : object
properties :
json :
x-kubernetes-preserve-unknown-fields : true
type : object
properties :
spec :
type : object
properties :
foo :
type : string
bar :
type : string
对于上述定义,如果提供的数值如下:
json :
spec :
foo : abc
bar : def
something : x
status :
something : x
则该值会被剪裁为:
json :
spec :
foo : abc
bar : def
status :
something : x
这意味着所指定的 spec 对象中的 something 字段被剪裁掉,而其外部的内容都被保留。
IntOrString 模式定义中标记了 x-kubernetes-int-or-string: true 的节点不受前述规则 1
约束,因此下面的定义是结构化的模式:
type : object
properties :
foo :
x-kubernetes-int-or-string : true
此外,所有这类节点也不再受规则 3 约束,也就是说,下面两种模式是被允许的
(注意,仅限于这两种模式,不支持添加新字段的任何其他变种):
x-kubernetes-int-or-string : true
anyOf :
- type : integer
- type : string
...
和
x-kubernetes-int-or-string : true
allOf :
- anyOf :
- type : integer
- type : string
- ... # zero or more
...
在以上两种规约中,整数值和字符串值都会被认为是合法的。
在合法性检查模式定义的发布时 ,
x-kubernetes-int-or-string: true 会被展开为上述两种模式之一。
RawExtension RawExtensions(就像在
k8s.io/apimachinery
项目中 runtime.RawExtension 所定义的那样)
可以保存完整的 Kubernetes 对象,也就是,其中会包含 apiVersion 和 kind
字段。
通过 x-kubernetes-embedded-resource: true 来设定这些嵌套对象的规约(无论是
完全无限制还是部分指定都可以)是可能的。例如:
type : object
properties :
foo :
x-kubernetes-embedded-resource : true
x-kubernetes-preserve-unknown-fields : true
这里,字段 foo 包含一个完整的对象,例如:
foo :
apiVersion : v1
kind : Pod
spec :
...
由于字段上设置了 x-kubernetes-preserve-unknown-fields: true,其中的内容不会
被剪裁。不过,在这个语境中,x-kubernetes-preserve-unknown-fields: true 的
使用是可选的。
设置了 x-kubernetes-embedded-resource: true 之后,apiVersion、kind 和
metadata 都是隐式设定并隐式完成合法性验证。
提供 CRD 的多个版本 关于如何为你的 CustomResourceDefinition 提供多个版本的支持,以及如何将你的对象
从一个版本迁移到另一个版本, 详细信息可参阅
定制资源定义的版本 。
高级主题 Finalizers Finalizer 能够让控制器实现异步的删除前(Pre-delete)回调。
定制对象和内置对象一样支持 Finalizer。
你可以像下面一样为定制对象添加 Finalizer:
apiVersion : "stable.example.com/v1"
kind : CronTab
metadata :
finalizers :
- stable.example.com/finalizer
自定义 Finalizer 的标识符包含一个域名、一个正向斜线和 finalizer 的名称。
任何控制器都可以在任何对象的 finalizer 列表中添加新的 finalizer。
对带有 Finalizer 的对象的第一个删除请求会为其 metadata.deletionTimestamp
设置一个值,但不会真的删除对象。一旦此值被设置,finalizers 列表中的表项
只能被移除。在列表中仍然包含 finalizer 时,无法强制删除对应的对象。
当 metadata.deletionTimestamp 字段被设置时,监视该对象的各个控制器会
执行它们所能处理的 finalizer,并在完成处理之后将其从列表中移除。
每个控制器负责将其 finalizer 从列表中删除。
metadata.deletionGracePeriodSeconds 的取值控制对更新的轮询周期。
一旦 finalizers 列表为空时,就意味着所有 finalizer 都被执行过,
Kubernetes 会最终删除该资源,
合法性检查 定制资源是通过
OpenAPI v3 模式定义
来执行合法性检查的,
你可以通过使用准入控制 Webhook
来添加额外的合法性检查逻辑。
此外,对模式定义存在以下限制:
以下字段不可设置:definitionsdependenciesdeprecateddiscriminatoridpatternPropertiesreadOnlywriteOnlyxml$ref 字段 uniqueItems 不可设置为 true 字段 additionalProperties 不可设置为 false 字段 additionalProperties 与 properties 互斥,不可同时使用 当设置默认值特性 被启用时,可以设置字段 default。
就 apiextensions.k8s.io/v1 组的 CustomResourceDefinitions,这一条件是满足的。
设置默认值的功能特性从 1.17 开始正式发布。该特性在 1.16 版本中处于
Beta 状态,要求 CustomResourceDefaulting
特性门控
被启用。对于大多数集群而言,Beta 状态的特性门控默认都是自动启用的。
关于对某些 CustomResourceDefinition 特性所必需的限制,可参见
结构化的模式定义 小节。
模式定义是在 CustomResourceDefinition 中设置的。在下面的例子中,
CustomResourceDefinition 对定制对象执行以下合法性检查:
spec.cronSpec 必须是一个字符串,必须是正则表达式所描述的形式;spec.replicas 必须是一个整数,且其最小值为 1、最大值为 10。将此 CustomResourceDefinition 保存到 resourcedefinition.yaml 文件中:
apiVersion : apiextensions.k8s.io/v1
kind : CustomResourceDefinition
metadata :
name : crontabs.stable.example.com
spec :
group : stable.example.com
versions :
- name : v1
served : true
storage : true
schema :
# openAPIV3Schema is the schema for validating custom objects.
openAPIV3Schema :
type : object
properties :
spec :
type : object
properties :
cronSpec :
type : string
pattern : '^(\d+|\*)(/\d+)?(\s+(\d+|\*)(/\d+)?){4}$'
image :
type : string
replicas :
type : integer
minimum : 1
maximum : 10
scope : Namespaced
names :
plural : crontabs
singular : crontab
kind : CronTab
shortNames :
- ct
并创建 CustomResourceDefinition:
kubectl apply -f resourcedefinition.yaml
对于一个创建 CronTab 类别对象的定制对象的请求而言,如果其字段中包含非法值,则
该请求会被拒绝。
在下面的例子中,定制对象中包含带非法值的字段:
spec.cronSpec 与正则表达式不匹配spec.replicas 数值大于 10。如果你将下面的 YAML 保存到 my-crontab.yaml:
apiVersion : "stable.example.com/v1"
kind : CronTab
metadata :
name : my-new-cron-object
spec :
cronSpec : "* * * *"
image : my-awesome-cron-image
replicas : 15
并尝试创建定制对象:
kubectl apply -f my-crontab.yaml
你会看到下面的错误信息:
The CronTab "my-new-cron-object" is invalid: []: Invalid value: map[string]interface {}{"apiVersion":"stable.example.com/v1", "kind":"CronTab", "metadata":map[string]interface {}{"name":"my-new-cron-object", "namespace":"default", "deletionTimestamp":interface {}(nil), "deletionGracePeriodSeconds":(*int64)(nil), "creationTimestamp":"2017-09-05T05:20:07Z", "uid":"e14d79e7-91f9-11e7-a598-f0761cb232d1", "clusterName":""}, "spec":map[string]interface {}{"cronSpec":"* * * *", "image":"my-awesome-cron-image", "replicas":15}}:
validation failure list:
spec.cronSpec in body should match '^(\d+|\*)(/\d+)?(\s+(\d+|\*)(/\d+)?){4}$'
spec.replicas in body should be less than or equal to 10
如果所有字段都包含合法值,则对象创建的请求会被接受。
将下面的 YAML 保存到 my-crontab.yaml 文件:
apiVersion : "stable.example.com/v1"
kind : CronTab
metadata :
name : my-new-cron-object
spec :
cronSpec : "* * * * */5"
image : my-awesome-cron-image
replicas : 5
并创建定制对象:
kubectl apply -f my-crontab.yaml
crontab "my-new-cron-object" created
设置默认值 说明: 要使用设置默认值功能,你的 CustomResourceDefinition 必须使用 API 版本 apiextensions.k8s.io/v1。
设置默认值的功能允许在 OpenAPI v3 合法性检查模式定义 中设置默认值:
apiVersion : apiextensions.k8s.io/v1
kind : CustomResourceDefinition
metadata :
name : crontabs.stable.example.com
spec :
group : stable.example.com
versions :
- name : v1
served : true
storage : true
schema :
# openAPIV3Schema 是用来检查定制对象的模式定义
openAPIV3Schema :
type : object
properties :
spec :
type : object
properties :
cronSpec :
type : string
pattern : '^(\d+|\*)(/\d+)?(\s+(\d+|\*)(/\d+)?){4}$'
default : "5 0 * * *"
image :
type : string
replicas :
type : integer
minimum : 1
maximum : 10
default : 1
scope : Namespaced
names :
plural : crontabs
singular : crontab
kind : CronTab
shortNames :
- ct
使用此 CRD 定义时,cronSpec 和 replicas 都会被设置默认值:
apiVersion : "stable.example.com/v1"
kind : CronTab
metadata :
name : my-new-cron-object
spec :
image : my-awesome-cron-image
会生成:
apiVersion : "stable.example.com/v1"
kind : CronTab
metadata :
name : my-new-cron-object
spec :
cronSpec : "5 0 * * *"
image : my-awesome-cron-image
replicas : 1
默认值设定的行为发生在定制对象上:
在向 API 服务器发送的请求中,基于请求版本的设定设置默认值; 在从 etcd 读取对象时,使用存储版本来设置默认值; 在 Mutating 准入控制插件执行非空的补丁操作时,基于准入 Webhook 对象
版本设置默认值。 从 etcd 中读取数据时所应用的默认值设置不会被写回到 etcd 中。
需要通过 API 执行更新请求才能将这种方式设置的默认值写回到 etcd。
默认值一定会被剪裁(除了 metadata 字段的默认值设置),且必须通过所提供
的模式定义的检查。
针对 x-kubernetes-embedded-resource: true 节点(或者包含 metadata 字段的结构的默认值)
的 metadata 字段的默认值设置不会在 CustomResourceDefinition 创建时被剪裁,
而是在处理请求的字段剪裁阶段被删除。
设置默认值和字段是否可为空(Nullable) 1.20 版本新增: 对于未设置其 nullable 标志的字段或者将该标志设置为
false 的字段,其空值(Null)会在设置默认值之前被剪裁掉。如果对应字段
存在默认值,则默认值会被赋予该字段。当 nullable 被设置为 true 时,
字段的空值会被保留,且不会在设置默认值时被覆盖。
例如,给定下面的 OpenAPI 模式定义:
type : object
properties :
spec :
type : object
properties :
foo :
type : string
nullable : false
default : "default"
bar :
type : string
nullable : true
baz :
type : string
像下面这样创建一个为 foo、bar 和 baz 设置空值的对象时:
spec :
foo : null
bar : null
baz : null
其结果会是这样:
spec :
foo : "default"
bar : null
其中的 foo 字段被剪裁掉并重新设置默认值,因为该字段是不可为空的。
bar 字段的 nullable: true 使得其能够保有其空值。
baz 字段则被完全剪裁掉,因为该字段是不可为空的,并且没有默认值设置。
以 OpenAPI v2 形式发布合法性检查模式 CustomResourceDefinition 的结构化的 、
启用了剪裁的 OpenAPI v3 合法性检查模式
会在 Kubernetes API 服务器上作为
OpenAPI v2 规约
的一部分发布出来。
kubectl 命令行工具会基于所发布的模式定义来执行
客户端的合法性检查(kubectl create 和 kubectl apply),为定制资源的模式定义
提供解释(kubectl explain)。
所发布的模式还可被用于其他目的,例如生成客户端或者生成文档。
OpenAPI v3 合法性检查模式定义会被转换为 OpenAPI v2 模式定义,并出现在
OpenAPI v2 规范
的 definitions 和 paths 字段中。
在转换过程中会发生以下修改,目的是保持与 1.13 版本以前的 kubectl 工具兼容。
这些修改可以避免 kubectl 过于严格,以至于拒绝它无法理解的 OpenAPI 模式定义。
转换过程不会更改 CRD 中定义的合法性检查模式定义,因此不会影响到 API 服务器中
的合法性检查 。
以下字段会被移除,因为它们在 OpenAPI v2 中不支持(在将来版本中将使用 OpenAPI v3,
因而不会有这些限制)字段 allOf、anyOf、oneOf 和 not 会被删除 如果设置了 nullable: true,我们会丢弃 type、nullable、items 和 properties
OpenAPI v2 无法表达 Nullable。为了避免 kubectl 拒绝正常的对象,这一转换是必要的。 额外的打印列 kubectl 工具依赖服务器端的输出格式化。你的集群的 API 服务器决定 kubectl get 命令要显示的列有哪些。
你可以为 CustomResourceDefinition 定制这些要打印的列。
下面的例子添加了 Spec、Replicas 和 Age 列:
将此 CustomResourceDefinition 保存到 resourcedefinition.yaml 文件:
apiVersion : apiextensions.k8s.io/v1
kind : CustomResourceDefinition
metadata :
name : crontabs.stable.example.com
spec :
group : stable.example.com
scope : Namespaced
names :
plural : crontabs
singular : crontab
kind : CronTab
shortNames :
- ct
versions :
- name : v1
served : true
storage : true
schema :
openAPIV3Schema :
type : object
properties :
spec :
type : object
properties :
cronSpec :
type : string
image :
type : string
replicas :
type : integer
additionalPrinterColumns :
- name : Spec
type : string
description : The cron spec defining the interval a CronJob is run
jsonPath : .spec.cronSpec
- name : Replicas
type : integer
description : The number of jobs launched by the CronJob
jsonPath : .spec.replicas
- name : Age
type : date
jsonPath : .metadata.creationTimestamp
创建 CustomResourceDefinition:
kubectl apply -f resourcedefinition.yaml
使用前文中的 my-crontab.yaml 创建一个实例。
启用服务器端打印输出:
kubectl get crontab my-new-cron-object
注意输出中的 NAME、SPEC、REPLICAS 和 AGE 列:
NAME SPEC REPLICAS AGE
my-new-cron-object * * * * * 1 7s
说明: NAME 列是隐含的,不需要在 CustomResourceDefinition 中定义。
优先级 每个列都包含一个 priority(优先级)字段。当前,优先级用来区分标准视图(Standard
View)和宽视图(Wide View)(使用 -o wide 标志)中显示的列:
优先级为 0 的列会在标准视图中显示。 优先级大于 0 的列只会在宽视图中显示。 类型 列的 type 字段可以是以下值之一
(比较 OpenAPI v3 数据类型 ):
integer – 非浮点数字number – 浮点数字string – 字符串boolean – true 或 falsedate – 显示为以自此时间戳以来经过的时长如果定制资源中的值与列中指定的类型不匹配,该值会被忽略。
你可以通过定制资源的合法性检查来确保取值类型是正确的。
列的 format 字段可以是以下值之一:
int32int64floatdoublebytedatedate-timepassword列的 format 字段控制 kubectl 打印对应取值时采用的风格。
子资源 定制资源支持 /status 和 /scale 子资源。
通过在 CustomResourceDefinition 中定义 status 和 scale,
可以有选择地启用这些子资源。
Status 子资源 当启用了 status 子资源时,对应定制资源的 /status 子资源会被暴露出来。
status 和 spec 内容分别用定制资源内的 .status 和 .spec JSON 路径来表达; 对 /status 子资源的 PUT 请求要求使用定制资源对象作为其输入,但会忽略
status 之外的所有内容。 对 /status 子资源的 PUT 请求仅对定制资源的 status 内容进行合法性检查。 对定制资源的 PUT、POST、PATCH 请求会忽略 status 内容的改变。 对所有变更请求,除非改变是针对 .metadata 或 .status,.metadata.generation
的取值都会增加。 Scale 子资源 当启用了 scale 子资源时,定制资源的 /scale 子资源就被暴露出来。
针对 /scale 所发送的对象是 autoscaling/v1.Scale。
为了启用 scale 子资源,CustomResourceDefinition 定义了以下字段:
在下面的例子中,status 和 scale 子资源都被启用。
将此 CustomResourceDefinition 保存到 resourcedefinition.yaml 文件:
apiVersion : apiextensions.k8s.io/v1
kind : CustomResourceDefinition
metadata :
name : crontabs.stable.example.com
spec :
group : stable.example.com
versions :
- name : v1
served : true
storage : true
schema :
openAPIV3Schema :
type : object
properties :
spec :
type : object
properties :
cronSpec :
type : string
image :
type : string
replicas :
type : integer
status :
type : object
properties :
replicas :
type : integer
labelSelector :
type : string
# subresources 描述定制资源的子资源
subresources :
# status 启用 status 子资源
status : {}
# scale 启用 scale 子资源
scale :
# specReplicasPath 定义定制资源中对应 scale.spec.replicas 的 JSON 路径
specReplicasPath : .spec.replicas
# statusReplicasPath 定义定制资源中对应 scale.status.replicas 的 JSON 路径
statusReplicasPath : .status.replicas
# labelSelectorPath 定义定制资源中对应 scale.status.selector 的 JSON 路径
labelSelectorPath : .status.labelSelector
scope : Namespaced
names :
plural : crontabs
singular : crontab
kind : CronTab
shortNames :
- ct
之后创建此 CustomResourceDefinition:
kubectl apply -f resourcedefinition.yaml
CustomResourceDefinition 对象创建完毕之后,你可以创建定制对象,。
如果你将下面的 YAML 保存到 my-crontab.yaml 文件:
apiVersion : "stable.example.com/v1"
kind : CronTab
metadata :
name : my-new-cron-object
spec :
cronSpec : "* * * * */5"
image : my-awesome-cron-image
replicas : 3
并创建定制对象:
kubectl apply -f my-crontab.yaml
那么会创建新的、命名空间作用域的 RESTful API 端点:
/apis/stable.example.com/v1/namespaces/*/crontabs/status
和
/apis/stable.example.com/v1/namespaces/*/crontabs/scale
定制资源可以使用 kubectl scale 命令来扩缩其规模。
例如下面的命令将前面创建的定制资源的 .spec.replicas 设置为 5:
kubectl scale --replicas= 5 crontabs/my-new-cron-object
crontabs "my-new-cron-object" scaled
kubectl get crontabs my-new-cron-object -o jsonpath = '{.spec.replicas}'
5
你可以使用 PodDisruptionBudget
来保护启用了 scale 子资源的定制资源。
分类 分类(Categories)是定制资源所归属的分组资源列表(例如,all)。
你可以使用 kubectl get <分类名称> 来列举属于某分类的所有资源。
下面的示例在 CustomResourceDefinition 中将 all 添加到分类列表中,
并展示了如何使用 kubectl get all 来输出定制资源:
将下面的 CustomResourceDefinition 保存到 resourcedefinition.yaml 文件中:
apiVersion : apiextensions.k8s.io/v1
kind : CustomResourceDefinition
metadata :
name : crontabs.stable.example.com
spec :
group : stable.example.com
versions :
- name : v1
served : true
storage : true
schema :
openAPIV3Schema :
type : object
properties :
spec :
type : object
properties :
cronSpec :
type : string
image :
type : string
replicas :
type : integer
scope : Namespaced
names :
plural : crontabs
singular : crontab
kind : CronTab
shortNames :
- ct
# categories 是定制资源所归属的分类资源列表
categories :
- all
之后创建此 CRD:
kubectl apply -f resourcedefinition.yaml
创建了 CustomResourceDefinition 对象之后,你可以创建定制对象。
将下面的 YAML 保存到 my-crontab.yaml 中:
apiVersion : "stable.example.com/v1"
kind : CronTab
metadata :
name : my-new-cron-object
spec :
cronSpec : "* * * * */5"
image : my-awesome-cron-image
并创建定制对象:
kubectl apply -f my-crontab.yaml
你可以在使用 kubectl get 时指定分类:
输出中会包含类别为 CronTab 的定制资源:
NAME AGE
crontabs/my-new-cron-object 3s
接下来 4.11.1.2 - CustomResourceDefinition 的版本 本页介绍如何添加版本信息到
CustomResourceDefinitions 。
目的是标明 CustomResourceDefinitions 的稳定级别或者服务于 API 升级。
API 升级时需要在不同 API 表示形式之间进行转换。
本页还描述如何将对象从一个版本升级到另一个版本。
准备开始 你必须拥有一个 Kubernetes 的集群,同时你的 Kubernetes 集群必须带有 kubectl 命令行工具。
如果你还没有集群,你可以通过 Minikube 构建一
个你自己的集群,或者你可以使用下面任意一个 Kubernetes 工具构建:
你应该对定制资源
有一些初步了解。
您的 Kubernetes 服务器版本必须不低于版本 v1.16.
要获知版本信息,请输入
kubectl version.
概览 CustomResourceDefinition API 提供了用于引入和升级的工作流程到 CustomResourceDefinition
的新版本。
创建 CustomResourceDefinition 时,会在 CustomResourceDefinition spec.versions
列表设置适当的稳定级别和版本号。例如,v1beta1 表示第一个版本尚未稳定。
所有定制资源对象将首先用这个版本保存。
创建 CustomResourceDefinition 后,客户端可以开始使用 v1beta1 API。
稍后可能需要添加新版本,例如 v1。
添加新版本:
选择一种转化策略。由于定制资源对象需要能够两种版本都可用,
这意味着它们有时会以与存储版本不同的版本来提供服务。为了能够做到这一点,
有时必须在它们存储的版本和提供的版本之间进行转换。如果转换涉及模式变更,
并且需要自定义逻辑,则应该使用 Webhook 来完成。如果没有模式变更,
则可使用默认的 None 转换策略,为不同版本提供服务时只有 apiVersion 字段
会被改变。 如果使用转换 Webhook,请创建并部署转换 Webhook。更多详细信息请参见
Webhook conversion 。 更新 CustomResourceDefinition,将新版本设置为 served:true,加入到
spec.versions 列表。另外,还要设置 spec.conversion 字段
为所选的转换策略。如果使用转换 Webhook,请配置
spec.conversion.webhookClientConfig 来调用 Webhook。 添加新版本后,客户端可以逐步迁移到新版本。让某些客户使用旧版本的同时
支持其他人使用新版本是相当安全的。
将存储的对象迁移到新版本:
请参阅将现有对象升级到新的存储版本 节。 对于客户来说,在将对象升级到新的存储版本之前、期间和之后使用旧版本和新版本都是安全的。
删除旧版本:
确保所有客户端都已完全迁移到新版本。
可以查看 kube-apiserver 的日志以识别仍通过旧版本进行访问的所有客户端。 在 spec.versions 列表中将旧版本的 served 设置为 false。
如果仍有客户端意外地使用旧版本,他们可能开始会报告采用旧版本尝试访
定制资源的错误消息。
如果发生这种情况,请将旧版本的served:true 恢复,然后迁移余下的客户端
使用新版本,然后重复此步骤。 确保已完成将现有对象升级到新存储版本
的步骤。在 CustomResourceDefinition 的 spec.versions 列表中,确认新版本的
stored 已被设置为 true。 确认旧版本不在 CustomResourceDefinition status.storedVersions 中。 从 CustomResourceDefinition spec.versions 列表中删除旧版本。 在转换 Webhooks 中放弃对旧版本的转换支持。 指定多个版本 CustomResourceDefinition API 的 versions 字段可用于支持你所开发的
定制资源的多个版本。版本可以具有不同的模式,并且转换 Webhooks
可以在多个版本之间转换定制资源。
在适当的情况下,Webhook 转换应遵循
Kubernetes API 约定 。
尤其是,请查阅
API 变更文档
以了解一些有用的常见错误和建议。
说明: 在 apiextensions.k8s.io/v1beta1 版本中曾经有一个 version 字段,
名字不叫做 versions。该 version 字段已经被废弃,成为可选项。
不过如果该字段不是空,则必须与 versions 字段中的第一个条目匹配。
下面的示例显示了两个版本的 CustomResourceDefinition。
第一个例子中假设所有的版本使用相同的模式而它们之间没有转换。
YAML 中的注释提供了更多背景信息。
apiVersion : apiextensions.k8s.io/v1
kind : CustomResourceDefinition
metadata :
# name 必须匹配后面 spec 中的字段,且使用格式 <plural>.<group>
name : crontabs.example.com
spec :
# 组名,用于 REST API: /apis/<group>/<version>
group : example.com
# 此 CustomResourceDefinition 所支持的版本列表
versions :
- name : v1beta1
# 每个 version 可以通过 served 标志启用或禁止
served : true
# 有且只能有一个 version 必须被标记为存储版本
storage : true
# schema 是必需字段
schema :
openAPIV3Schema :
type : object
properties :
host :
type : string
port :
type : string
- name : v1
served : true
storage : false
schema :
openAPIV3Schema :
type : object
properties :
host :
type : string
port :
type : string
# conversion 节是 Kubernetes 1.13+ 版本引入的,其默认值为无转换,即
# strategy 子字段设置为 None。
conversion :
# None 转换假定所有版本采用相同的模式定义,仅仅将定制资源的 apiVersion
# 设置为合适的值.
strategy : None
# 可以是 Namespaced 或 Cluster
scope : Namespaced
names :
# 名称的复数形式,用于 URL: /apis/<group>/<version>/<plural>
plural : crontabs
# 名称的单数形式,用于在命令行接口和显示时作为其别名
singular : crontab
# kind 通常是驼峰编码(CamelCased)的单数形式,用于资源清单中
kind : CronTab
# shortNames 允许你在命令行接口中使用更短的字符串来匹配你的资源
shortNames :
- ct
# 在 v1.16 中被弃用以推荐使用 apiextensions.k8s.io/v1
apiVersion : apiextensions.k8s.io/v1beta1
kind : CustomResourceDefinition
metadata :
# name 必须匹配后面 spec 中的字段,且使用格式 <plural>.<group>
name : crontabs.example.com
spec :
# 组名,用于 REST API: /apis/<group>/<version>
group : example.com
# 此 CustomResourceDefinition 所支持的版本列表
versions :
- name : v1beta1
# 每个 version 可以通过 served 标志启用或禁止
served : true
# 有且只能有一个 version 必须被标记为存储版本
storage : true
- name : v1
served : true
storage : false
validation :
openAPIV3Schema :
type : object
properties :
host :
type : string
port :
type : string
# conversion 节是 Kubernetes 1.13+ 版本引入的,其默认值为无转换,即
# strategy 子字段设置为 None。
conversion :
# None 转换假定所有版本采用相同的模式定义,仅仅将定制资源的 apiVersion
# 设置为合适的值.
strategy : None
# 可以是 Namespaced 或 Cluster
scope : Namespaced
names :
# 名称的复数形式,用于 URL: /apis/<group>/<version>/<plural>
plural : crontabs
# 名称的单数形式,用于在命令行接口和显示时作为其别名
singular : crontab
# kind 通常是驼峰编码(CamelCased)的单数形式,用于资源清单中
kind : CronTab
# shortNames 允许你在命令行接口中使用更短的字符串来匹配你的资源
shortNames :
- ct
你可以将 CustomResourceDefinition 存储在 YAML 文件中,然后使用
kubectl apply 来创建它。
kubectl apply -f my-versioned-crontab.yaml
在创建之后,API 服务器开始在 HTTP REST 端点上为每个已启用的版本提供服务。
在上面的示例中,API 版本可以在 /apis/example.com/v1beta1 和
/apis/example.com/v1 处获得。
版本优先级 不考虑 CustomResourceDefinition 中版本被定义的顺序,kubectl 使用
具有最高优先级的版本作为访问对象的默认版本。
通过解析 name 字段确定优先级来决定版本号,稳定性(GA、Beta 或 Alpha)
级别及该稳定性级别内的序列。
用于对版本进行排序的算法在设计上与 Kubernetes 项目对 Kubernetes 版本进行排序的方式相同。
版本以 v 开头跟一个数字,一个可选的 beta 或者 alpha 和一个可选的附加数字
作为版本信息。
从广义上讲,版本字符串可能看起来像 v2 或者 v2beta1。
使用以下算法对版本进行排序:
遵循 Kubernetes 版本模式的条目在不符合条件的条目之前进行排序。 对于遵循 Kubernetes 版本模式的条目,版本字符串的数字部分从最大到最小排序。 如果第一个数字后面有字符串 beta 或 alpha,它们首先按去掉 beta 或
alpha 之后的版本号排序(相当于 GA 版本),之后按 beta 先、alpha 后的顺序排序, 如果 beta 或 alpha 之后还有另一个数字,那么也会针对这些数字
从大到小排序。 不符合上述格式的字符串按字母顺序排序,数字部分不经过特殊处理。
请注意,在下面的示例中,foo1 排在 foo10 之前。
这与遵循 Kubernetes 版本模式的条目的数字部分排序不同。 如果查看以下版本排序列表,这些规则就容易懂了:
- v10
- v2
- v1
- v11beta2
- v10beta3
- v3beta1
- v12alpha1
- v11alpha2
- foo1
- foo10
对于指定多个版本 中的示例,版本排序顺序为
v1,后跟着 v1beta1。
这导致了 kubectl 命令使用 v1 作为默认版本,除非所提供的对象指定了版本。
版本废弃 FEATURE STATE: Kubernetes v1.19 [stable]
从 v1.19 开始,CustomResourceDefinition 可用来标明所定义的资源的特定版本
被废弃。当发起对已废弃的版本的 API 请求时,会在 API 响应中以 HTTP 头部
的形式返回警告消息。
如果需要,可以对资源的每个废弃版本定制该警告消息。
定制的警告消息应该标明废弃的 API 组、版本和类别(kind),并且应该标明
应该使用(如果有的话)哪个 API 组、版本和类别作为替代。
apiVersion : apiextensions.k8s.io/v1
kind : CustomResourceDefinition
name : crontabs.example.com
spec :
group : example.com
names :
plural : crontabs
singular : crontab
kind : CronTab
scope : Namespaced
versions :
- name : v1alpha1
served : true
# 此属性标明此定制资源的 v1alpha1 版本已被弃用。
# 发给此版本的 API 请求会在服务器响应中收到警告消息头。
deprecated : true
# 此属性设置用来覆盖返回给发送 v1alpha1 API 请求的客户端的默认警告信息。
deprecationWarning : "example.com/v1alpha1 CronTab is deprecated; see http://example.com/v1alpha1-v1 for instructions to migrate to example.com/v1 CronTab"
schema : ...
- name : v1beta1
served : true
# 此属性标明该定制资源的 v1beta1 版本已被弃用。
# 发给此版本的 API 请求会在服务器响应中收到警告消息头。
# 针对此版本的请求所返回的是默认的警告消息。
deprecated : true
schema : ...
- name : v1
served : true
storage : true
schema : ...
# 在 v1.16 中弃用以推荐使用 apiextensions.k8s.io/v1
apiVersion : apiextensions.k8s.io/v1beta1
kind : CustomResourceDefinition
metadata :
name : crontabs.example.com
spec :
group : example.com
names :
plural : crontabs
singular : crontab
kind : CronTab
scope : Namespaced
validation : ...
versions :
- name : v1alpha1
served : true
# 此属性标明此定制资源的 v1alpha1 版本已被弃用。
# 发给此版本的 API 请求会在服务器响应中收到警告消息头。
deprecated : true
# 此属性设置用来覆盖返回给发送 v1alpha1 API 请求的客户端的默认警告信息。
deprecationWarning : "example.com/v1alpha1 CronTab is deprecated; see http://example.com/v1alpha1-v1 for instructions to migrate to example.com/v1 CronTab"
- name : v1beta1
served : true
# 此属性标明该定制资源的 v1beta1 版本已被弃用。
# 发给此版本的 API 请求会在服务器响应中收到警告消息头。
# 针对此版本的请求所返回的是默认的警告消息。
deprecated : true
- name : v1
served : true
storage : true
Webhook 转换 FEATURE STATE: Kubernetes v1.16 [stable]
说明: Webhook 转换在 Kubernetes 1.13 版本引入,在 Kubernetes 1.15 中成为 Beta 功能。
要使用此功能,应启用
CustomResourceWebhookConversion 特性。
在大多数集群上,这类 Beta 特性应该是自动启用的。
请参阅
特性门控
文档以获得更多信息。
上面的例子在版本之间有一个 None 转换,它只在转换时设置 apiVersion 字段
而不改变对象的其余部分。API 服务器还支持在需要转换时调用外部服务的 webhook 转换。
例如:
定制资源的请求版本与其存储版本不同。 使用某版本创建了 Watch 请求,但所更改对象以另一版本存储。 定制资源的 PUT 请求所针对版本与存储版本不同。 为了涵盖所有这些情况并优化 API 服务器所作的转换,转换请求可以包含多个对象,
以便减少外部调用。Webhook 应该独立执行各个转换。
编写一个转换 Webhook 服务器 请参考定制资源转换 Webhook 服务器
的实现;该实现在 Kubernetes e2e 测试中得到验证。
Webhook 处理由 API 服务器发送的 ConversionReview 请求,并在
ConversionResponse 中封装发回转换结果。
请注意,请求包含需要独立转换的定制资源列表,这些对象在被转换之后不能改变其
在列表中的顺序。该示例服务器的组织方式使其可以复用于其他转换。
大多数常见代码都位于
framework 文件
中,只留下
一个函数
用于实现不同的转换。
说明: 转换 Webhook 服务器示例中将
ClientAuth 字段设置为
空 ,
默认为
NoClientCert。
这意味着 webhook 服务器没有验证客户端(也就是 API 服务器)的身份。
如果你需要双向 TLS 或者其他方式来验证客户端,请参阅如何
验证 API 服务 。
被允许的变更 转换 Webhook 不可以更改被转换对象的 metadata 中除 labels 和 annotations
之外的任何属性。
尝试更改 name、UID 和 namespace 时都会导致引起转换的请求失败。
所有其他变更只是被忽略而已。
部署转换 Webhook 服务 用于部署转换 webhook 的文档与
准入 Webhook 服务示例 相同。
这里的假设是转换 Webhook 服务器被部署为 default 名字空间中名为
example-conversion-webhook-server 的服务,并在路径 /crdconvert
上处理请求。
说明: 当 Webhook 服务器作为一个服务被部署到 Kubernetes 集群中时,它必须
通过端口 443 公开其服务(服务器本身可以使用任意端口,但是服务对象
应该将它映射到端口 443)。
如果为服务器使用不同的端口,则 API 服务器和 Webhook 服务器之间的通信
可能会失败。
配置 CustomResourceDefinition 以使用转换 Webhook 通过修改 spec 中的 conversion 部分,可以扩展 None 转换示例来
使用转换 Webhook。
apiVersion : apiextensions.k8s.io/v1
kind : CustomResourceDefinition
metadata :
# name 必须匹配后面 spec 中的字段,且使用格式 <plural>.<group>
name : crontabs.example.com
spec :
# 组名,用于 REST API: /apis/<group>/<version>
group : example.com
# 此 CustomResourceDefinition 所支持的版本列表
versions :
- name : v1beta1
# 每个 version 可以通过 served 标志启用或禁止
served : true
# 有且只能有一个 version 必须被标记为存储版本
storage : true
# 当不存在顶级模式定义时,每个版本(version)可以定义其自身的模式
schema :
openAPIV3Schema :
type : object
properties :
hostPort :
type : string
- name : v1
served : true
storage : false
schema :
openAPIV3Schema :
type : object
properties :
host :
type : string
port :
type : string
conversion :
# Webhook strategy 告诉 API 服务器调用外部 Webhook 来完成定制资源
# 之间的转换
strategy : Webhook
# 当 strategy 为 "Webhook" 时,webhook 属性是必需的
# 该属性配置将被 API 服务器调用的 Webhook 端点
webhook :
# conversionReviewVersions 标明 Webhook 所能理解或偏好使用的
# ConversionReview 对象版本。
# API 服务器所能理解的列表中的第一个版本会被发送到 Webhook
# Webhook 必须按所接收到的版本响应一个 ConversionReview 对象
conversionReviewVersions : ["v1" ,"v1beta1" ]
clientConfig :
service :
namespace : default
name : example-conversion-webhook-server
path : /crdconvert
caBundle : "Ci0tLS0tQk...<base64-encoded PEM bundle>...tLS0K"
# 可以是 Namespaced 或 Cluster
scope : Namespaced
names :
# 名称的复数形式,用于 URL: /apis/<group>/<version>/<plural>
plural : crontabs
# 名称的单数形式,用于在命令行接口和显示时作为其别名
singular : crontab
# kind 通常是驼峰编码(CamelCased)的单数形式,用于资源清单中
kind : CronTab
# shortNames 允许你在命令行接口中使用更短的字符串来匹配你的资源
shortNames :
- ct
# 在 v1.16 中被弃用以推荐使用 apiextensions.k8s.io/v1
apiVersion : apiextensions.k8s.io/v1beta1
kind : CustomResourceDefinition
metadata :
# name 必须匹配后面 spec 中的字段,且使用格式 <plural>.<group>
name : crontabs.example.com
spec :
# 组名,用于 REST API: /apis/<group>/<version>
group : example.com
# 裁剪掉下面的 OpenAPI 模式中未曾定义的对象字段
preserveUnknownFields : false
# 此 CustomResourceDefinition 所支持的版本列表
versions :
- name : v1beta1
# 每个 version 可以通过 served 标志启用或禁止
served : true
# 有且只能有一个 version 必须被标记为存储版本
storage : true
# 当不存在顶级模式定义时,每个版本(version)可以定义其自身的模式
schema :
openAPIV3Schema :
type : object
properties :
hostPort :
type : string
- name : v1
served : true
storage : false
schema :
openAPIV3Schema :
type : object
properties :
host :
type : string
port :
type : string
conversion :
# Webhook strategy 告诉 API 服务器调用外部 Webhook 来完成定制资源
strategy : Webhook
# 当 strategy 为 "Webhook" 时,webhookClientConfig 属性是必需的
# 该属性配置将被 API 服务器调用的 Webhook 端点
webhookClientConfig :
service :
namespace : default
name : example-conversion-webhook-server
path : /crdconvert
caBundle : "Ci0tLS0tQk...<base64-encoded PEM bundle>...tLS0K"
# 可以是 Namespaced 或 Cluster
scope : Namespaced
names :
# 名称的复数形式,用于 URL: /apis/<group>/<version>/<plural>
plural : crontabs
# 名称的单数形式,用于在命令行接口和显示时作为其别名
singular : crontab
# kind 通常是驼峰编码(CamelCased)的单数形式,用于资源清单中
kind : CronTab
# shortNames 允许你在命令行接口中使用更短的字符串来匹配你的资源
shortNames :
- ct
你可以将 CustomResourceDefinition 保存在 YAML 文件中,然后使用
kubectl apply 来应用它。
kubectl apply -f my-versioned-crontab-with-conversion.yaml
在应用新更改之前,请确保转换服务器已启动并正在运行。
调用 Webhook API 服务器一旦确定请求应发送到转换 Webhook,它需要知道如何调用 Webhook。
这是在 webhookClientConfig 中指定的 Webhook 配置。
转换 Webhook 可以通过 URL 或服务引用来调用,并且可以选择包含自定义 CA 包,
以用于验证 TLS 连接。
URL url 以标准 URL 形式给出 Webhook 的位置(scheme://host:port/path)。
host 不应引用集群中运行的服务,而应通过指定 service 字段来提供
服务引用。
在某些 API 服务器中,host 可以通过外部 DNS 进行解析(即
kube-apiserver 无法解析集群内 DNS,那样会违反分层规则)。
host 也可以是 IP 地址。
请注意,除非你非常小心地在所有运行着可能调用 Webhook 的 API 服务器的
主机上运行此 Webhook,否则将 localhost 或 127.0.0.1 用作 host
是风险很大的。这样的安装很可能是不可移植的,即很难在新集群中启用。
HTTP 协议必须为 https;URL 必须以 https:// 开头。
尝试使用用户或基本身份验证(例如,使用user:password@)是不允许的。
URL 片段(#...)和查询参数(?...)也是不允许的。
下面是为调用 URL 来执行转换 Webhook 的示例,其中期望使用系统信任根
来验证 TLS 证书,因此未指定 caBundle:
apiVersion : apiextensions.k8s.io/v1
kind : CustomResourceDefinition
...
spec :
...
conversion :
strategy : Webhook
webhook :
clientConfig :
url : "https://my-webhook.example.com:9443/my-webhook-path"
...
# 在 v1.16 中已弃用以推荐使用 apiextensions.k8s.io/v1
apiVersion : apiextensions.k8s.io/v1beta1
kind : CustomResourceDefinition
...
spec :
...
conversion :
strategy : Webhook
webhookClientConfig :
url : "https://my-webhook.example.com:9443/my-webhook-path"
...
服务引用 webhookClientConfig 内部的 service 段是对转换 Webhook 服务的引用。
如果 Webhook 在集群中运行,则应使用 service 而不是 url。
服务的名字空间和名称是必需的。端口是可选的,默认为 443。
路径是可选的,默认为/。
下面配置中,服务配置为在端口 1234、子路径 /my-path 上被调用。
例子中针对 ServerName my-service-name.my-service-namespace.svc,
使用自定义 CA 包验证 TLS 连接。
apiVersion : apiextensions.k8s.io/v1
kind : CustomResourceDefinition
...
spec :
...
conversion :
strategy : Webhook
webhook :
clientConfig :
service :
namespace : my-service-namespace
name : my-service-name
path : /my-path
port : 1234
caBundle : "Ci0tLS0tQk...<base64-encoded PEM bundle>...tLS0K"
...
# v1.16 中被弃用以推荐使用 apiextensions.k8s.io/v1
apiVersion : apiextensions.k8s.io/v1beta1
kind : CustomResourceDefinition
...
spec :
...
conversion :
strategy : Webhook
webhookClientConfig :
service :
namespace : my-service-namespace
name : my-service-name
path : /my-path
port : 1234
caBundle : "Ci0tLS0tQk...<base64-encoded PEM bundle>...tLS0K"
...
Webhook 请求和响应 请求 向 Webhooks 发起请求的动词是 POST,请求的 Content-Type 为 application/json。
请求的主题为 JSON 序列化形式的
apiextensions.k8s.io API 组的 ConversionReview API 对象。
Webhooks 可以在其 CustomResourceDefinition 中使用conversionReviewVersions 字段
设置它们接受的 ConversionReview 对象的版本:
apiVersion : apiextensions.k8s.io/v1
kind : CustomResourceDefinition
...
spec :
...
conversion :
strategy : Webhook
webhook :
conversionReviewVersions : ["v1" , "v1beta1" ]
...
创建 apiextensions.k8s.io/v1 版本的自定义资源定义时,
conversionReviewVersions是必填字段。
Webhooks 要求支持至少一个 ConversionReview 当前和以前的 API 服务器
可以理解的版本。
# v1.16 已弃用以推荐使用 apiextensions.k8s.io/v1
apiVersion : apiextensions.k8s.io/v1beta1
kind : CustomResourceDefinition
...
spec :
...
conversion :
strategy : Webhook
conversionReviewVersions : ["v1" , "v1beta1" ]
...
创建 apiextensions.k8s.io/v1beta1 定制资源定义时若未指定
conversionReviewVersions,则默认值为 v1beta1。
API 服务器将 conversionReviewVersions 列表中他们所支持的第一个
ConversionReview 资源版本发送给 Webhook。
如果列表中的版本都不被 API 服务器支持,则无法创建自定义资源定义。
如果某 API 服务器遇到之前创建的转换 Webhook 配置,并且该配置不支持
API 服务器知道如何发送的任何 ConversionReview 版本,调用 Webhook
的尝试会失败。
下面的示例显示了包含在 ConversionReview 对象中的数据,
该请求意在将 CronTab 对象转换为 example.com/v1:
apiVersion : apiextensions.k8s.io/v1
kind : ConversionReview
request :
# 用来唯一标识此转换调用的随机 UID
uid : 705ab4f5-6393-11e8-b7cc-42010a800002
# 对象要转换到的目标 API 组和版本
desiredAPIVersion : example.com/v1
# 要转换的对象列表
# 其中可能包含一个或多个对象,版本可能相同也可能不同
objects :
- kind : CronTab
apiVersion : example.com/v1beta1
metadata :
creationTimestamp : "2019-09-04T14:03:02Z"
name : local-crontab
namespace : default
resourceVersion : "143"
uid : "3415a7fc-162b-4300-b5da-fd6083580d66"
hostPort : "localhost:1234"
- kind : CronTab
apiVersion : example.com/v1beta1
metadata :
creationTimestamp : "2019-09-03T13:02:01Z"
name : remote-crontab
resourceVersion : "12893" ,
uid : "359a83ec-b575-460d-b553-d859cedde8a0"
hostPort : example.com:2345
# v1.16 中已废弃以推荐使用 apiextensions.k8s.io/v1
apiVersion : apiextensions.k8s.io/v1beta1
kind : ConversionReview
request :
# 用来唯一标识此转换调用的随机 UID
uid : 705ab4f5-6393-11e8-b7cc-42010a800002
# 对象要转换到的目标 API 组和版本
desiredAPIVersion : example.com/v1
# 要转换的对象列表
# 其中可能包含一个或多个对象,版本可能相同也可能不同
objects :
- kind : CronTab
apiVersion : example.com/v1beta1
metadata :
creationTimestamp : "2019-09-04T14:03:02Z"
name : local-crontab
namespace : default
resourceVersion : "143"
uid : "3415a7fc-162b-4300-b5da-fd6083580d66"
hostPort : "localhost:1234"
- kind : CronTab
apiVersion : example.com/v1beta1
metadata :
creationTimestamp : "2019-09-03T13:02:01Z"
name : remote-crontab
resourceVersion : "12893" ,
uid : "359a83ec-b575-460d-b553-d859cedde8a0"
hostPort : example.com:2345
响应 Webhooks 响应包含 200 HTTP 状态代码、Content-Type: application/json,
在主体中包含 JSON 序列化形式的数据,在 response 节中给出
ConversionReview 对象(与发送的版本相同)。
如果转换成功,则 Webhook 应该返回包含以下字段的 response 节:
uid,从发送到 webhook 的 request.uid 复制而来result,设置为 {"status":"Success"}}convertedObjects,包含来自 request.objects 的所有对象,均已转换为
request.desiredVersionWebhook 的最简单成功响应示例:
apiVersion : apiextensions.k8s.io/v1
kind : ConversionReview
response :
# 必须与 <request.uid> 匹配
uid : "705ab4f5-6393-11e8-b7cc-42010a800002"
result :
status : Success
# 这里的对象必须与 request.objects 中的对象顺序相同并且其 apiVersion
# 被设置为 <request.desiredAPIVersion>。
# kind、metadata.uid、metadata.name 和 metadata.namespace 等字段都不可
# 被 Webhook 修改。
# Webhook 可以更改 metadata.labels 和 metadata.annotations 字段值
# Webhook 对 metadata 中其他字段的更改都会被忽略
convertedObjects :
- kind : CronTab
apiVersion : example.com/v1
metadata :
creationTimestamp : "2019-09-04T14:03:02Z"
name : local-crontab
namespace : default
resourceVersion : "143" ,
uid : "3415a7fc-162b-4300-b5da-fd6083580d66"
host : localhost
port : "1234"
- kind : CronTab
apiVersion : example.com/v1
metadata :
creationTimestamp : "2019-09-03T13:02:01Z" ,
name : remote-crontab
resourceVersion : "12893" ,
uid : "359a83ec-b575-460d-b553-d859cedde8a0"
host : example.com
port : "2345"
# v1.16 中已弃用以推荐使用 apiextensions.k8s.io/v1
apiVersion : apiextensions.k8s.io/v1beta1
kind : ConversionReview
response :
# 必须与 <request.uid> 匹配
uid : "705ab4f5-6393-11e8-b7cc-42010a800002"
result :
status : Failed
# 这里的对象必须与 request.objects 中的对象顺序相同并且其 apiVersion
# 被设置为 <request.desiredAPIVersion>。
# kind、metadata.uid、metadata.name 和 metadata.namespace 等字段都不可
# 被 Webhook 修改。
# Webhook 可以更改 metadata.labels 和 metadata.annotations 字段值
# Webhook 对 metadata 中其他字段的更改都会被忽略
convertedObjects :
- kind : CronTab
apiVersion : example.com/v1
metadata :
creationTimestamp : "2019-09-04T14:03:02Z"
name : local-crontab
namespace : default
resourceVersion : "143" ,
uid : "3415a7fc-162b-4300-b5da-fd6083580d66"
host : localhost
port : "1234"
- kind : CronTab
apiVersion : example.com/v1
metadata :
creationTimestamp : "2019-09-03T13:02:01Z" ,
name : remote-crontab
resourceVersion : "12893" ,
uid : "359a83ec-b575-460d-b553-d859cedde8a0"
host : example.com
port : "2345"
如果转换失败,则 Webhook 应该返回包含以下字段的 response 节:
*uid,从发送到 Webhook 的 request.uid 复制而来
*result,设置为 {"status": "Failed"}
警告: 转换失败会破坏对定制资源的读写访问,包括更新或删除资源的能力。
转换失败应尽可能避免,并且不可用于实施合法性检查约束
(应改用验证模式或 Webhook 准入插件)。
来自 Webhook 的响应示例,指示转换请求失败,并带有可选消息:
apiVersion : apiextensions.k8s.io/v1
kind : ConversionReview
response :
uid : <value from request.uid>
result : {
status : Failed
message : hostPort could not be parsed into a separate host and port
# v1.16 中弃用以推荐使用 apiextensions.k8s.io/v1
apiVersion : apiextensions.k8s.io/v1beta1
kind : ConversionReview
response :
uid : <value from request.uid>
result :
status : Failed
message : hostPort could not be parsed into a separate host and port
编写、读取和更新版本化的 CustomResourceDefinition 对象 写入对象时,将使用写入时指定的存储版本来存储。如果存储版本发生变化,
现有对象永远不会被自动转换。然而,新创建或被更新的对象将以新的存储版本写入。
对象写入的版本不再被支持是有可能的。
当读取对象时,作为路径的一部分,你需要指定版本。
如果所指定的版本与对象的持久版本不同,Kubernetes 会按所请求的版本将对象返回,
但是在满足服务请求时,被持久化的对象既不会在磁盘上更改,也不会以任何方式进行
转换(除了 apiVersion 字符串被更改之外)。你可以以当前提供的任何版本
来请求对象。
如果你更新一个现有对象,它将以当前的存储版本被重写。
这是可以将对象从一个版本改到另一个版本的唯一办法。
为了说明这一点,请考虑以下假设的一系列事件:
存储版本是 v1beta1。你创建一个对象。该对象以版本 v1beta1 存储。 你将为 CustomResourceDefinition 添加版本 v1,并将其指定为存储版本。 你使用版本 v1beta1 来读取你的对象,然后你再次用版本 v1 读取对象。
除了 apiVersion 字段之外,返回的两个对象是完全相同的。 你创建一个新对象。对象以版本 v1 保存在存储中。
你现在有两个对象,其中一个是 v1beta1,另一个是 v1。 你更新第一个对象。该对象现在以版本 v1 保存,因为 v1 是当前的存储版本。 以前的存储版本 API 服务器在状态字段 storedVersions 中记录曾被标记为存储版本的每个版本。
对象可能以任何曾被指定为存储版本的版本保存。
存储中不会出现从未成为存储版本的版本的对象。
将现有对象升级到新的存储版本 弃用版本并删除其支持时,请设计存储升级过程。
选项 1: 使用存储版本迁移程序(Storage Version Migrator)
运行存储版本迁移程序 从 CustomResourceDefinition 的 status.storedVersions 字段中去掉
老的版本。 选项 2: 手动将现有对象升级到新的存储版本
以下是从 v1beta1 升级到 v1 的示例过程。
在 CustomResourceDefinition 文件中将 v1 设置为存储版本,并使用 kubectl 应用它。
storedVersions现在是v1beta1, v1。 编写升级过程以列出所有现有对象并使用相同内容将其写回存储。
这会强制后端使用当前存储版本(即 v1)写入对象。 通过从 storedVersions 字段中删除 v1beta1 来更新 CustomResourceDefinition
的Status。 4.11.2 - 配置聚合层 配置聚合层
可以允许 Kubernetes apiserver 使用其它 API 扩展,这些 API 不是核心
Kubernetes API 的一部分。
准备开始
你必须拥有一个 Kubernetes 的集群,同时你的 Kubernetes 集群必须带有 kubectl 命令行工具。
如果你还没有集群,你可以通过 Minikube 构建一
个你自己的集群,或者你可以使用下面任意一个 Kubernetes 工具构建:
要获知版本信息,请输入
kubectl version.
说明: 要使聚合层在你的环境中正常工作以支持代理服务器和扩展 apiserver 之间的相互 TLS 身份验证,
需要满足一些设置要求。Kubernetes 和 kube-apiserver 具有多个 CA,
因此请确保代理是由聚合层 CA 签名的,而不是由主 CA 签名的。
注意: 对不同的客户端类型重复使用相同的 CA 会对群集的功能产生负面影响。
有关更多信息,请参见
CA 重用和冲突 。
身份认证流程 与自定义资源定义(CRD)不同,除标准的 Kubernetes apiserver 外,Aggregation API
还涉及另一个服务器:扩展 apiserver。
Kubernetes apiserver 将需要与你的扩展 apiserver 通信,并且你的扩展 apiserver
也需要与 Kubernetes apiserver 通信。
为了确保此通信的安全,Kubernetes apiserver 使用 x509 证书向扩展 apiserver 认证。
本节介绍身份认证和鉴权流程的工作方式以及如何配置它们。
大致流程如下:
Kubernetes apiserver:对发出请求的用户身份认证,并对请求的 API 路径执行鉴权。 Kubernetes apiserver:将请求转发到扩展 apiserver 扩展 apiserver:认证来自 Kubernetes apiserver 的请求 扩展 apiserver:对来自原始用户的请求鉴权 扩展 apiserver:执行 本节的其余部分详细描述了这些步骤。
该流程可以在下图中看到。
.
以上泳道的来源可以在本文档的源码中找到。
Kubernetes Apiserver 认证和授权 由扩展 apiserver 服务的对 API 路径的请求以与所有 API 请求相同的方式开始:
与 Kubernetes apiserver 的通信。该路径已通过扩展 apiserver 在
Kubernetes apiserver 中注册。
用户与 Kubernetes apiserver 通信,请求访问路径。
Kubernetes apiserver 使用它的标准认证和授权配置来对用户认证,以及对特定路径的鉴权。
有关对 Kubernetes 集群认证的概述,请参见
对集群认证 。
有关对Kubernetes群集资源的访问鉴权的概述,请参见
鉴权概述 。
到目前为止,所有内容都是标准的 Kubernetes API 请求,认证与鉴权。
Kubernetes apiserver 现在准备将请求发送到扩展 apiserver。
Kubernetes Apiserver 代理请求 Kubernetes apiserver 现在将请求发送或代理到注册以处理该请求的扩展 apiserver。
为此,它需要了解几件事:
Kubernetes apiserver 应该如何向扩展 apiserver 认证,以通知扩展
apiserver 通过网络发出的请求来自有效的 Kubernetes apiserver?
Kubernetes apiserver 应该如何通知扩展 apiserver 原始请求
已通过认证的用户名和组?
为提供这两条信息,你必须使用若干标志来配置 Kubernetes apiserver。
Kubernetes Apiserver 客户端认证 Kubernetes apiserver 通过 TLS 连接到扩展 apiserver,并使用客户端证书认证。
你必须在启动时使用提供的标志向 Kubernetes apiserver 提供以下内容:
通过 --proxy-client-key-file 指定私钥文件 通过 --proxy-client-cert-file 签名的客户端证书文件 通过 --requestheader-client-ca-file 签署客户端证书文件的 CA 证书 通过 --requestheader-allowed-names 在签署的客户证书中有效的公用名(CN) Kubernetes apiserver 将使用由 --proxy-client-*-file 指示的文件来验证扩展 apiserver。
为了使合规的扩展 apiserver 能够将该请求视为有效,必须满足以下条件:
连接必须使用由 CA 签署的客户端证书,该证书的证书位于 --requestheader-client-ca-file 中。 连接必须使用客户端证书,该客户端证书的 CN 是 --requestheader-allowed-names 中列出的证书之一。 说明: 你可以将此选项设置为空白,即为--requestheader-allowed-names。
这将向扩展 apiserver 指示任何 CN 是可接受的。
使用这些选项启动时,Kubernetes apiserver 将:
使用它们向扩展 apiserver 认证。 在 kube-system 命名空间中
创建一个名为 extension-apiserver-authentication 的 ConfigMap,
它将在其中放置 CA 证书和允许的 CN。
反过来,扩展 apiserver 可以检索这些内容以验证请求。 请注意,Kubernetes apiserver 使用相同的客户端证书对所有扩展 apiserver 认证。
它不会为每个扩展 apiserver 创建一个客户端证书,而是创建一个证书作为
Kubernetes apiserver 认证。所有扩展 apiserver 请求都重复使用相同的请求。
原始请求用户名和组 当 Kubernetes apiserver 将请求代理到扩展 apiserver 时,
它将向扩展 apiserver 通知原始请求已成功通过其验证的用户名和组。
它在其代理请求的 HTTP 头部中提供这些。你必须将要使用的标头名称告知
Kubernetes apiserver。
通过--requestheader-username-headers 标明用来保存用户名的头部 通过--requestheader-group-headers 标明用来保存 group 的头部 通过--requestheader-extra-headers-prefix 标明用来保存拓展信息前缀的头部 这些头部名称也放置在 extension-apiserver-authentication ConfigMap 中,
因此扩展 apiserver 可以检索和使用它们。
扩展 Apiserver 认证 扩展 apiserver 在收到来自 Kubernetes apiserver 的代理请求后,
必须验证该请求确实确实来自有效的身份验证代理,
该认证代理由 Kubernetes apiserver 履行。扩展 apiserver 通过以下方式对其认证:
如上所述,从kube-system中的 configmap 中检索以下内容:
客户端 CA 证书 允许名称(CN)列表 用户名,组和其他信息的头部 使用以下证书检查 TLS 连接是否已通过认证:
由其证书与检索到的 CA 证书匹配的 CA 签名。 在允许的 CN 列表中有一个 CN,除非列表为空,在这种情况下允许所有 CN。 从适当的头部中提取用户名和组 如果以上均通过,则该请求是来自合法认证代理(在本例中为 Kubernetes apiserver)
的有效代理请求。
请注意,扩展 apiserver 实现负责提供上述内容。
默认情况下,许多扩展 apiserver 实现利用 k8s.io/apiserver/ 软件包来做到这一点。
也有一些实现可能支持使用命令行选项来覆盖这些配置。
为了具有检索 configmap 的权限,扩展 apiserver 需要适当的角色。
在 kube-system 名字空间中有一个默认角色
extension-apiserver-authentication-reader 可用于设置。
扩展 Apiserver 对请求鉴权 扩展 apiserver 现在可以验证从标头检索的user/group是否有权执行给定请求。
通过向 Kubernetes apiserver 发送标准
SubjectAccessReview 请求来实现。
为了使扩展 apiserver 本身被鉴权可以向 Kubernetes apiserver 提交 SubjectAccessReview 请求,
它需要正确的权限。
Kubernetes 包含一个具有相应权限的名为 system:auth-delegator 的默认 ClusterRole,
可以将其授予扩展 apiserver 的服务帐户。
扩展 Apiserver 执行 如果 SubjectAccessReview 通过,则扩展 apiserver 执行请求。
启用 Kubernetes Apiserver 标志 通过以下 kube-apiserver 标志启用聚合层。
你的服务提供商可能已经为你完成了这些工作:
--requestheader-client-ca-file=<path to aggregator CA cert>
--requestheader-allowed-names=front-proxy-client
--requestheader-extra-headers-prefix=X-Remote-Extra-
--requestheader-group-headers=X-Remote-Group
--requestheader-username-headers=X-Remote-User
--proxy-client-cert-file=<path to aggregator proxy cert>
--proxy-client-key-file=<path to aggregator proxy key>
CA-重用和冲突 Kubernetes apiserver 有两个客户端 CA 选项:
--client-ca-file--requestheader-client-ca-file这些功能中的每个功能都是独立的;如果使用不正确,可能彼此冲突。
--client-ca-file:当请求到达 Kubernetes apiserver 时,如果启用了此选项,
则 Kubernetes apiserver 会检查请求的证书。
如果它是由 --client-ca-file 引用的文件中的 CA 证书之一签名的,
并且用户是公用名CN=的值,而组是组织O= 的取值,则该请求被视为合法请求。
请参阅关于 TLS 身份验证的文档 。
--requestheader-client-ca-file:当请求到达 Kubernetes apiserver 时,
如果启用此选项,则 Kubernetes apiserver 会检查请求的证书。
如果它是由文件引用中的 --requestheader-client-ca-file 所签署的 CA 证书之一签名的,
则该请求将被视为潜在的合法请求。
然后,Kubernetes apiserver 检查通用名称 CN= 是否是
--requestheader-allowed-names 提供的列表中的名称之一。
如果名称允许,则请求被批准;如果不是,则请求被拒绝。
如果同时提供了 --client-ca-file 和 --requestheader-client-ca-file,
则首先检查 --requestheader-client-ca-file CA,然后再检查--client-ca-file。
通常,这些选项中的每一个都使用不同的 CA(根 CA 或中间 CA)。
常规客户端请求与 --client-ca-file 相匹配,而聚合请求要与
--requestheader-client-ca-file 相匹配。
但是,如果两者都使用同一个 CA,则通常会通过 --client-ca-file
传递的客户端请求将失败,因为 CA 将与 --requestheader-client-ca-file
中的 CA 匹配,但是通用名称 CN= 将不匹配 --requestheader-allowed-names
中可接受的通用名称之一。
这可能导致你的 kubelet 和其他控制平面组件以及最终用户无法向 Kubernetes
apiserver 认证。
因此,请对用于控制平面组件和最终用户鉴权的 --client-ca-file 选项和
用于聚合 apiserver 鉴权的 --requestheader-client-ca-file 选项使用
不同的 CA 证书。
警告: 除非你了解风险和保护 CA 用法的机制,否则 不要 重用在不同上下文中使用的 CA。
如果你未在运行 API 服务器的主机上运行 kube-proxy,则必须确保使用以下
kube-apiserver 标志启用系统:
--enable-aggregator-routing=true
注册 APIService 对象 你可以动态配置将哪些客户端请求代理到扩展 apiserver。以下是注册示例:
apiVersion : apiregistration.k8s.io/v1
kind : APIService
metadata :
name : <注释对象名称>
spec :
group : <扩展 Apiserver 的 API 组名>
version : <扩展 Apiserver 的 API 版本>
groupPriorityMinimum : <APIService 对应组的优先级, 参考 API 文档>
versionPriority : <版本在组中的优先排序, 参考 API 文档>
service :
namespace : <拓展 Apiserver 服务的名字空间>
name : <拓展 Apiserver 服务的名称>
caBundle : <PEM 编码的 CA 证书,用于对 Webhook 服务器的证书签名>
APIService 对象的名称必须是合法的
路径片段名称 。
调用扩展 apiserver 一旦 Kubernetes apiserver 确定应将请求发送到扩展 apiserver,
它需要知道如何调用它。
service 部分是对扩展 apiserver 的服务的引用。
服务的名字空间和名字是必需的。端口是可选的,默认为 443。
路径配置是可选的,默认为 /。
下面是为可在端口 1234 上调用的扩展 apiserver 的配置示例
服务位于子路径 /my-path 下,并针对 ServerName
my-service-name.my-service-namespace.svc
使用自定义的 CA 包来验证 TLS 连接
使用自定义 CA 捆绑包的my-service-name.my-service-namespace.svc。
apiVersion : apiregistration.k8s.io/v1
kind : APIService
...
spec :
...
service :
namespace : my-service-namespace
name : my-service-name
port : 1234
caBundle : "Ci0tLS0tQk...<base64-encoded PEM bundle>...tLS0K"
...
接下来 4.11.3 - 安装一个扩展的 API server 安装扩展的 API 服务器来使用聚合层以让 Kubernetes API 服务器使用
其它 API 进行扩展,
这些 API 不是核心 Kubernetes API 的一部分。
准备开始
你必须拥有一个 Kubernetes 的集群,同时你的 Kubernetes 集群必须带有 kubectl 命令行工具。
如果你还没有集群,你可以通过 Minikube 构建一
个你自己的集群,或者你可以使用下面任意一个 Kubernetes 工具构建:
要获知版本信息,请输入
kubectl version.
你必须配置聚合层
并且启用 API 服务器的相关参数。 安装一个扩展的 API 服务器来使用聚合层 以下步骤描述如何 在一个高层次 设置一个扩展的 apiserver。无论你使用的是 YAML 配置还是使用 API,这些步骤都适用。
目前我们正在尝试区分出两者的区别。有关使用 YAML 配置的具体示例,你可以在 Kubernetes 库中查看
sample-apiserver 。
或者,你可以使用现有的第三方解决方案,例如
apiserver-builder ,
它将生成框架并自动执行以下所有步骤。
确保启用了 APIService API(检查 --runtime-config)。默认应该是启用的,除非被特意关闭了。 你可能需要制定一个 RBAC 规则,以允许你添加 APIService 对象,或让你的集群管理员创建一个。
(由于 API 扩展会影响整个集群,因此不建议在实时集群中对 API 扩展进行测试/开发/调试) 创建 Kubernetes 命名空间,扩展的 api-service 将运行在该命名空间中。 创建(或获取)用来签署服务器证书的 CA 证书,扩展 api-server 中将使用该证书做 HTTPS 连接。 为 api-server 创建一个服务端的证书(或秘钥)以使用 HTTPS。这个证书应该由上述的 CA 签署。
同时应该还要有一个 Kube DNS 名称的 CN,这是从 Kubernetes 服务派生而来的,
格式为 <service name>.<service name namespace>.svc。 使用命名空间中的证书(或秘钥)创建一个 Kubernetes secret。 为扩展 api-server 创建一个 Kubernetes Deployment,并确保以卷的方式挂载了 Secret。
它应该包含对扩展 api-server 镜像的引用。Deployment 也应该在同一个命名空间中。 确保你的扩展 apiserver 从该卷中加载了那些证书,并在 HTTPS 握手过程中使用它们。 在你的命令空间中创建一个 Kubernetes 服务账号。 为资源允许的操作创建 Kubernetes 集群角色。 用你命令空间中的服务账号创建一个 Kubernetes 集群角色绑定,绑定到你刚创建的角色上。 用你命令空间中的服务账号创建一个 Kubernetes 集群角色绑定,绑定到 system:auth-delegator
集群角色,以将 auth 决策委派给 Kubernetes 核心 API 服务器。 以你命令空间中的服务账号创建一个 Kubernetes 集群角色绑定,绑定到
extension-apiserver-authentication-reader 角色。
这将让你的扩展 api-server 能够访问 extension-apiserver-authentication configmap。 创建一个 Kubernetes apiservice。
上述的 CA 证书应该使用 base64 编码,剥离新行并用作 apiservice 中的 spec.caBundle。
该资源不应放到任何名字空间。如果使用了
kube-aggregator API ,那么只需要传入
PEM 编码的 CA 绑定,因为 base 64 编码已经完成了。 使用 kubectl 来获得你的资源。
它应该返回 "找不到资源"。此消息表示一切正常,但你目前还没有创建该资源类型的对象。 接下来 4.11.4 - 配置多个调度器 Kubernetes 自带了一个默认调度器,其详细描述请查阅
这里 。
如果默认调度器不适合你的需求,你可以实现自己的调度器。
不仅如此,你甚至可以和默认调度器一起同时运行多个调度器,并告诉 Kubernetes 为每个
Pod 使用哪个调度器。
让我们通过一个例子讲述如何在 Kubernetes 中运行多个调度器。
关于实现调度器的具体细节描述超出了本文范围。
请参考 kube-scheduler 的实现,规范示例代码位于
pkg/scheduler 。
准备开始
你必须拥有一个 Kubernetes 的集群,同时你的 Kubernetes 集群必须带有 kubectl 命令行工具。
如果你还没有集群,你可以通过 Minikube 构建一
个你自己的集群,或者你可以使用下面任意一个 Kubernetes 工具构建:
要获知版本信息,请输入
kubectl version.
打包调度器 将调度器可执行文件打包到容器镜像中。出于示例目的,我们就使用默认调度器
(kube-scheduler)作为我们的第二个调度器。
克隆 Github 上 Kubernetes 源代码 ,
并编译构建源代码。
git clone https://github.com/kubernetes/kubernetes.git
cd kubernetes
make
创建一个包含 kube-scheduler 二进制文件的容器镜像。用于构建镜像的 Dockerfile 内容如下:
FROM busybox
ADD ./_output/dockerized/bin/linux/amd64/kube-scheduler /usr/local/bin/kube-scheduler
将文件保存为 Dockerfile,构建镜像并将其推送到镜像仓库。
此示例将镜像推送到 Google 容器镜像仓库(GCR) 。
有关详细信息,请阅读 GCR 文档 。
docker build -t gcr.io/my-gcp-project/my-kube-scheduler:1.0 .
gcloud docker -- push gcr.io/my-gcp-project/my-kube-scheduler:1.0
为调度器定义 Kubernetes Deployment 现在我们将调度器放在容器镜像中,我们可以为它创建一个 Pod 配置,并在我们的 Kubernetes 集群中
运行它。但是与其在集群中直接创建一个 Pod,不如使用
Deployment 。
Deployment 管理一个 ReplicaSet ,
ReplicaSet 再管理 Pod,从而使调度器能够免受一些故障的影响。
以下是 Deployment 配置,将其保存为 my-scheduler.yaml:
apiVersion : v1
kind : ServiceAccount
metadata :
name : my-scheduler
namespace : kube-system
---
apiVersion : rbac.authorization.k8s.io/v1
kind : ClusterRoleBinding
metadata :
name : my-scheduler-as-kube-scheduler
subjects :
- kind : ServiceAccount
name : my-scheduler
namespace : kube-system
roleRef :
kind : ClusterRole
name : system:kube-scheduler
apiGroup : rbac.authorization.k8s.io
---
apiVersion : rbac.authorization.k8s.io/v1
kind : ClusterRoleBinding
metadata :
name : my-scheduler-as-volume-scheduler
subjects :
- kind : ServiceAccount
name : my-scheduler
namespace : kube-system
roleRef :
kind : ClusterRole
name : system:volume-scheduler
apiGroup : rbac.authorization.k8s.io
---
apiVersion : apps/v1
kind : Deployment
metadata :
labels :
component : scheduler
tier : control-plane
name : my-scheduler
namespace : kube-system
spec :
selector :
matchLabels :
component : scheduler
tier : control-plane
replicas : 1
template :
metadata :
labels :
component : scheduler
tier : control-plane
version : second
spec :
serviceAccountName : my-scheduler
containers :
- command :
- /usr/local/bin/kube-scheduler
- --address=0.0.0.0
- --leader-elect=false
- --scheduler-name=my-scheduler
image : gcr.io/my-gcp-project/my-kube-scheduler:1.0
livenessProbe :
httpGet :
path : /healthz
port : 10251
initialDelaySeconds : 15
name : kube-second-scheduler
readinessProbe :
httpGet :
path : /healthz
port : 10251
resources :
requests :
cpu : '0.1'
securityContext :
privileged : false
volumeMounts : []
hostNetwork : false
hostPID : false
volumes : []
这里需要注意的是,在容器规约中配置的调度器启动命令参数(--scheduler-name)所指定的
调度器名称应该是唯一的。
这个名称应该与 Pod 上的可选参数 spec.schedulerName 的值相匹配,也就是说调度器名称的匹配
关系决定了 Pods 的调度任务由哪个调度器负责。
还要注意,我们创建了一个专用服务账号 my-scheduler 并将集群角色 system:kube-scheduler
绑定到它,以便它可以获得与 kube-scheduler 相同的权限。
请参阅 kube-scheduler 文档 以获取其他命令行参数的详细说明。
在集群中运行第二个调度器 为了在 Kubernetes 集群中运行我们的第二个调度器,只需在 Kubernetes 集群中创建上面配置中指定的 Deployment:
kubectl create -f my-scheduler.yaml
验证调度器 Pod 正在运行:
kubectl get pods --namespace= kube-system
输出类似于:
NAME READY STATUS RESTARTS AGE
....
my-scheduler-lnf4s-4744f 1/1 Running 0 2m
...
此列表中,除了默认的 kube-scheduler Pod 之外,你应该还能看到处于 “Running” 状态的
my-scheduler Pod。
启用领导者选举 要在启用了 leader 选举的情况下运行多调度器,你必须执行以下操作:
首先,更新上述 Deployment YAML(my-scheduler.yaml)文件中的以下字段:
--leader-elect=true--lock-object-namespace=lock-object-namespace--lock-object-name=lock-object-name如果在集群上启用了 RBAC,则必须更新 system:kube-scheduler 集群角色。
将调度器名称添加到应用于端点资源的规则的 resourceNames,如以下示例所示:
kubectl edit clusterrole system:kube-scheduler
apiVersion : rbac.authorization.k8s.io/v1
kind : ClusterRole
metadata :
annotations :
rbac.authorization.kubernetes.io/autoupdate : "true"
labels :
kubernetes.io/bootstrapping : rbac-defaults
name : system:kube-scheduler
rules :
- apiGroups :
- coordination.k8s.io
resources :
- leases
verbs :
- create
- apiGroups :
- coordination.k8s.io
resourceNames :
- kube-scheduler
- my-scheduler
resources :
- leases
verbs :
- get
- update
- apiGroups :
- ""
resourceNames :
- kube-scheduler
- my-scheduler
resources :
- endpoints
verbs :
- delete
- get
- patch
- update
为 Pod 指定调度器 现在我们的第二个调度器正在运行,让我们创建一些 Pod,并指定它们由默认调度器或我们刚部署的
调度器进行调度。
为了使用特定的调度器调度给定的 Pod,我们在那个 Pod 的规约中指定调度器的名称。让我们看看三个例子。
Pod spec 设置为 default-scheduler
apiVersion : v1
kind : Pod
metadata :
name : annotation-default-scheduler
labels :
name : multischeduler-example
spec :
schedulerName : default-scheduler
containers :
- name : pod-with-default-annotation-container
image : k8s.gcr.io/pause:2.0
通过将调度器名称作为 spec.schedulerName 参数的值来指定调度器。
在这种情况下,我们提供默认调度器的名称,即 default-scheduler。
将此文件另存为 pod2.yaml,并将其提交给 Kubernetes 集群。
kubectl create -f pod2.yaml
Pod spec 设置为 my-scheduler
apiVersion : v1
kind : Pod
metadata :
name : annotation-second-scheduler
labels :
name : multischeduler-example
spec :
schedulerName : my-scheduler
containers :
- name : pod-with-second-annotation-container
image : k8s.gcr.io/pause:2.0
在这种情况下,我们指定此 pod 使用我们部署的 my-scheduler 来调度。
请注意,spec.schedulerName 参数的值应该与 Deployment 中配置的提供给
scheduler 命令的参数名称匹配。
将此文件另存为 pod3.yaml,并将其提交给 Kubernetes 集群。
kubectl create -f pod3.yaml
确认所有三个 pod 都在运行。
验证是否使用所需的调度器调度了 pod 为了更容易地完成这些示例,我们没有验证 Pod 实际上是使用所需的调度程序调度的。
我们可以通过更改 Pod 的顺序和上面的部署配置提交来验证这一点。
如果我们在提交调度器部署配置之前将所有 Pod 配置提交给 Kubernetes 集群,
我们将看到注解了 annotation-second-scheduler 的 Pod 始终处于 “Pending” 状态,
而其他两个 Pod 被调度。
一旦我们提交调度器部署配置并且我们的新调度器开始运行,注解了
annotation-second-scheduler 的 pod 就能被调度。
或者,可以查看事件日志中的 “Scheduled” 条目,以验证是否由所需的调度器调度了 Pod。
4.11.5 - 使用 HTTP 代理访问 Kubernetes API 本文说明如何使用 HTTP 代理访问 Kubernetes API。
准备开始 如果您的集群中还没有任何应用,使用如下命令启动一个 Hello World 应用: kubectl create deployment node-hello --image= gcr.io/google-samples/node-hello:1.0 --port= 8080
使用 kubectl 启动代理服务器 使用如下命令启动 Kubernetes API 服务器的代理:
kubectl proxy --port=8080
探究 Kubernetes API 当代理服务器在运行时,你可以通过 curl、wget 或者浏览器访问 API。
获取 API 版本:
curl http://localhost:8080/api/
输出应该类似这样:
{
"kind": "APIVersions",
"versions": [
"v1"
],
"serverAddressByClientCIDRs": [
{
"clientCIDR": "0.0.0.0/0",
"serverAddress": "10.0.2.15:8443"
}
]
}
获取 Pod 列表:
curl http://localhost:8080/api/v1/namespaces/default/pods
{
"kind": "PodList",
"apiVersion": "v1",
"metadata": {
"resourceVersion": "33074"
},
"items": [
{
"metadata": {
"name": "kubernetes-bootcamp-2321272333-ix8pt",
"generateName": "kubernetes-bootcamp-2321272333-",
"namespace": "default",
"uid": "ba21457c-6b1d-11e6-85f7-1ef9f1dab92b",
"resourceVersion": "33003",
"creationTimestamp": "2016-08-25T23:43:30Z",
"labels": {
"pod-template-hash": "2321272333",
"run": "kubernetes-bootcamp"
},
...
}
接下来 想了解更多信息,请参阅 kubectl 代理 。
4.11.6 - 设置 Konnectivity 服务 Konnectivity 服务为控制平面提供集群通信的 TCP 级别代理。
准备开始 你必须拥有一个 Kubernetes 的集群,同时你的 Kubernetes 集群必须带有 kubectl 命令行工具。
如果你还没有集群,你可以通过 Minikube 构建一
个你自己的集群,或者你可以使用下面任意一个 Kubernetes 工具构建:
配置 Konnectivity 服务 接下来的步骤需要出口配置,比如:
apiVersion : apiserver.k8s.io/v1beta1
kind : EgressSelectorConfiguration
egressSelections :
# Since we want to control the egress traffic to the cluster, we use the
# "cluster" as the name. Other supported values are "etcd", and "master".
- name : cluster
connection :
# This controls the protocol between the API Server and the Konnectivity
# server. Supported values are "GRPC" and "HTTPConnect". There is no
# end user visible difference between the two modes. You need to set the
# Konnectivity server to work in the same mode.
proxyProtocol : GRPC
transport :
# This controls what transport the API Server uses to communicate with the
# Konnectivity server. UDS is recommended if the Konnectivity server
# locates on the same machine as the API Server. You need to configure the
# Konnectivity server to listen on the same UDS socket.
# The other supported transport is "tcp". You will need to set up TLS
# config to secure the TCP transport.
uds :
udsName : /etc/srv/kubernetes/konnectivity-server/konnectivity-server.socket
你需要配置 API 服务器来使用 Konnectivity 服务,并将网络流量定向到集群节点:
确保 ServiceAccountTokenVolumeProjection
特性门控
被启用。你可以通过为 kube-apiserver 提供以下标志启用
服务账号令牌卷保护 :
--service-account-issuer=api
--service-account-signing-key-file=/etc/kubernetes/pki/sa.key
--api-audiences=system:konnectivity-server
创建一个出站流量配置文件,比如 admin/konnectivity/egress-selector-configuration.yaml。
将 API 服务器的 --egress-selector-config-file 参数设置为你的 API 服务器的
离站流量配置文件路径。
如果你在使用 UDS 连接,须将卷配置添加到 kube-apiserver:
spec :
containers :
volumeMounts :
- name : konnectivity-uds
mountPath : /etc/kubernetes/konnectivity-server
readOnly : false
volumes :
- name : konnectivity-uds
hostPath :
path : /etc/kubernetes/konnectivity-server
type : DirectoryOrCreate
为 konnectivity-server 生成或者取得证书和 kubeconfig 文件。
例如,你可以使用 OpenSSL 命令行工具,基于存放在某控制面主机上
/etc/kubernetes/pki/ca.crt 文件中的集群 CA 证书来
发放一个 X.509 证书,
openssl req -subj "/CN=system:konnectivity-server" -new -newkey rsa:2048 -nodes -out konnectivity.csr -keyout konnectivity.key -out konnectivity.csr
openssl x509 -req -in konnectivity.csr -CA /etc/kubernetes/pki/ca.crt -CAkey /etc/kubernetes/pki/ca.key -CAcreateserial -out konnectivity.crt -days 375 -sha256
SERVER = $( kubectl config view -o jsonpath = '{.clusters..server}' )
kubectl --kubeconfig /etc/kubernetes/konnectivity-server.conf config set-credentials system:konnectivity-server --client-certificate konnectivity.crt --client-key konnectivity.key --embed-certs= true
kubectl --kubeconfig /etc/kubernetes/konnectivity-server.conf config set-cluster kubernetes --server " $SERVER " --certificate-authority /etc/kubernetes/pki/ca.crt --embed-certs= true
kubectl --kubeconfig /etc/kubernetes/konnectivity-server.conf config set-context system:konnectivity-server@kubernetes --cluster kubernetes --user system:konnectivity-server
kubectl --kubeconfig /etc/kubernetes/konnectivity-server.conf config use-context system:konnectivity-server@kubernetes
rm -f konnectivity.crt konnectivity.key konnectivity.csr
接下来,你需要部署 Konnectivity 服务器和代理。
kubernetes-sigs/apiserver-network-proxy
是一个参考实现。
在控制面节点上部署 Konnectivity 服务。
下面提供的 konnectivity-server.yaml 配置清单假定在你的集群中
Kubernetes 组件都是部署为静态 Pod 的。
如果不是,你可以将 Konnectivity 服务部署为 DaemonSet。
apiVersion : v1
kind : Pod
metadata :
name : konnectivity-server
namespace : kube-system
spec :
priorityClassName : system-cluster-critical
hostNetwork : true
containers :
- name : konnectivity-server-container
image : us.gcr.io/k8s-artifacts-prod/kas-network-proxy/proxy-server:v0.0.8
command : ["/proxy-server" ]
args : [
"--log-file=/var/log/konnectivity-server.log" ,
"--logtostderr=false" ,
"--log-file-max-size=0" ,
# This needs to be consistent with the value set in egressSelectorConfiguration.
"--uds-name=/etc/srv/kubernetes/konnectivity-server/konnectivity-server.socket" ,
# The following two lines assume the Konnectivity server is
# deployed on the same machine as the apiserver, and the certs and
# key of the API Server are at the specified location.
"--cluster-cert=/etc/srv/kubernetes/pki/apiserver.crt" ,
"--cluster-key=/etc/srv/kubernetes/pki/apiserver.key" ,
# This needs to be consistent with the value set in egressSelectorConfiguration.
"--mode=grpc" ,
"--server-port=0" ,
"--agent-port=8132" ,
"--admin-port=8133" ,
"--agent-namespace=kube-system" ,
"--agent-service-account=konnectivity-agent" ,
"--kubeconfig=/etc/srv/kubernetes/konnectivity-server/kubeconfig" ,
"--authentication-audience=system:konnectivity-server"
]
livenessProbe :
httpGet :
scheme : HTTP
host : 127.0.0.1
port : 8133
path : /healthz
initialDelaySeconds : 30
timeoutSeconds : 60
ports :
- name : agentport
containerPort : 8132
hostPort : 8132
- name : adminport
containerPort : 8133
hostPort : 8133
volumeMounts :
- name : varlogkonnectivityserver
mountPath : /var/log/konnectivity-server.log
readOnly : false
- name : pki
mountPath : /etc/srv/kubernetes/pki
readOnly : true
- name : konnectivity-uds
mountPath : /etc/srv/kubernetes/konnectivity-server
readOnly : false
volumes :
- name : varlogkonnectivityserver
hostPath :
path : /var/log/konnectivity-server.log
type : FileOrCreate
- name : pki
hostPath :
path : /etc/srv/kubernetes/pki
- name : konnectivity-uds
hostPath :
path : /etc/srv/kubernetes/konnectivity-server
type : DirectoryOrCreate
在你的集群中部署 Konnectivity 代理:
apiVersion : apps/v1
# Alternatively, you can deploy the agents as Deployments. It is not necessary
# to have an agent on each node.
kind : DaemonSet
metadata :
labels :
addonmanager.kubernetes.io/mode : Reconcile
k8s-app : konnectivity-agent
namespace : kube-system
name : konnectivity-agent
spec :
selector :
matchLabels :
k8s-app : konnectivity-agent
template :
metadata :
labels :
k8s-app : konnectivity-agent
spec :
priorityClassName : system-cluster-critical
tolerations :
- key : "CriticalAddonsOnly"
operator : "Exists"
containers :
- image : us.gcr.io/k8s-artifacts-prod/kas-network-proxy/proxy-agent:v0.0.8
name : konnectivity-agent
command : ["/proxy-agent" ]
args : [
"--logtostderr=true" ,
"--ca-cert=/var/run/secrets/kubernetes.io/serviceaccount/ca.crt" ,
# Since the konnectivity server runs with hostNetwork=true,
# this is the IP address of the master machine.
"--proxy-server-host=35.225.206.7" ,
"--proxy-server-port=8132" ,
"--service-account-token-path=/var/run/secrets/tokens/konnectivity-agent-token"
]
volumeMounts :
- mountPath : /var/run/secrets/tokens
name : konnectivity-agent-token
livenessProbe :
httpGet :
port : 8093
path : /healthz
initialDelaySeconds : 15
timeoutSeconds : 15
serviceAccountName : konnectivity-agent
volumes :
- name : konnectivity-agent-token
projected :
sources :
- serviceAccountToken :
path : konnectivity-agent-token
audience : system:konnectivity-server
最后,如果你的集群启用了 RBAC,请创建相关的 RBAC 规则:
apiVersion : rbac.authorization.k8s.io/v1
kind : ClusterRoleBinding
metadata :
name : system:konnectivity-server
labels :
kubernetes.io/cluster-service : "true"
addonmanager.kubernetes.io/mode : Reconcile
roleRef :
apiGroup : rbac.authorization.k8s.io
kind : ClusterRole
name : system:auth-delegator
subjects :
- apiGroup : rbac.authorization.k8s.io
kind : User
name : system:konnectivity-server
---
apiVersion : v1
kind : ServiceAccount
metadata :
name : konnectivity-agent
namespace : kube-system
labels :
kubernetes.io/cluster-service : "true"
addonmanager.kubernetes.io/mode : Reconcile
4.12 - TLS 了解如何使用传输层安全性( TLS )保护集群中的流量。
4.12.1 - 为 kubelet 配置证书轮换 本文展示如何在 kubelet 中启用并配置证书轮换。
FEATURE STATE: Kubernetes v1.19 [stable]
准备开始 要求 Kubernetes 1.8.0 或更高的版本 概述 Kubelet 使用证书进行 Kubernetes API 的认证。
默认情况下,这些证书的签发期限为一年,所以不需要太频繁地进行更新。
Kubernetes 1.8 版本中包含 beta 特性
kubelet 证书轮换 ,
在当前证书即将过期时,
将自动生成新的秘钥,并从 Kubernetes API 申请新的证书。 一旦新的证书可用,它将被用于与
Kubernetes API 间的连接认证。
启用客户端证书轮换 kubelet 进程接收 --rotate-certificates 参数,该参数决定 kubelet 在当前使用的
证书即将到期时,是否会自动申请新的证书。
kube-controller-manager 进程接收 --cluster-signing-duration 参数
(在 1.19 版本之前为 --experimental-cluster-signing-duration),用来
控制签发证书的有效期限。
理解证书轮换配置 当 kubelet 启动时,如被配置为自举(使用--bootstrap-kubeconfig 参数),kubelet
会使用其初始证书连接到 Kubernetes API ,并发送证书签名的请求。
可以通过以下方式查看证书签名请求的状态:
最初,来自节点上 kubelet 的证书签名请求处于 Pending 状态。 如果证书签名请求满足特定条件,
控制器管理器会自动批准,此时请求会处于 Approved 状态。 接下来,控制器管理器会签署证书,
证书的有效期限由 --cluster-signing-duration 参数指定,签署的证书会被附加到证书签名请求中。
Kubelet 会从 Kubernetes API 取回签署的证书,并将其写入磁盘,存储位置通过 --cert-dir
参数指定。
然后 kubelet 会使用新的证书连接到 Kubernetes API。
当签署的证书即将到期时,kubelet 会使用 Kubernetes API,发起新的证书签名请求。
同样地,控制器管理器会自动批准证书请求,并将签署的证书附加到证书签名请求中。 Kubelet
会从 Kubernetes API 取回签署的证书,并将其写入磁盘。 然后它会更新与 Kubernetes API
的连接,使用新的证书重新连接到 Kubernetes API。
4.12.2 - 手动轮换 CA 证书 本页展示如何手动轮换证书机构(CA)证书。
准备开始
你必须拥有一个 Kubernetes 的集群,同时你的 Kubernetes 集群必须带有 kubectl 命令行工具。
如果你还没有集群,你可以通过 Minikube 构建一
个你自己的集群,或者你可以使用下面任意一个 Kubernetes 工具构建:
您的 Kubernetes 服务器版本必须不低于版本 v1.13.
要获知版本信息,请输入
kubectl version.
要了解 Kubernetes 中用户认证的更多信息,参阅
认证 ; 要了解与 CA 证书最佳实践有关的更多信息,参阅单根 CA 。 手动轮换 CA 证书 注意: 确保备份你的证书目录、配置文件以及其他必要文件。
这里的方法假定 Kubernetes 的控制面通过运行多个 API 服务器以高可用配置模式运行。
另一假定是 API 服务器可体面地终止,因而客户端可以彻底地与一个 API 服务器断开
连接并连接到另一个 API 服务器。
如果集群中只有一个 API 服务器,则在 API 服务器重启期间会经历服务中断期。
将新的 CA 证书和私钥(例如:ca.crt、ca.key、front-proxy-ca.crt 和
front-proxy-client.key)分发到所有控制面节点,放在其 Kubernetes 证书目录下。 更新 kube-controller-manager 的
--root-ca-file 标志,使之同时包含老的和新的 CA,之后重启组件。
自此刻起,所创建的所有服务账号都会获得同时包含老的 CA 和新的 CA 的 Secret。
说明: kube-controller-manager 标志 --client-ca-file 和 --cluster-signing-cert-file 所引用的文件
不能是 CA 证书包。如果这些标志和 --root-ca-file 指向同一个 ca.crt 包文件(包含老的和新的 CA 证书),
你将会收到出错信息。
要解决这个问题,可以将新的 CA 证书复制到单独的文件中,并将 --client-ca-file 和 --cluster-signing-cert-file
标志指向该副本。一旦 ca.crt 不再是证书包文件,就可以恢复有问题的标志指向 ca.crt 并删除该副本。
更新所有服务账号令牌,使之同时包含老的和新的 CA 证书。
如果在 API 服务器使用新的 CA 之前启动了新的 Pod,这些 Pod
也会获得此更新并且同时信任老的和新的 CA 证书。
base64_encoded_ca = " $( base64 -w0 <path to file containing both old and new CAs>) "
for namespace in $( kubectl get ns --no-headers | awk '{print $1}' ) ; do
for token in $( kubectl get secrets --namespace " $namespace " --field-selector type = kubernetes.io/service-account-token -o name) ; do
kubectl get $token --namespace " $namespace " -o yaml | \
/bin/sed "s/\(ca.crt:\).*/\1 ${ base64_encoded_ca } /" | \
kubectl apply -f -
done
done
重启所有使用集群内配置的 Pods(例如:kube-proxy、coredns 等),以便这些 Pod 能够使用
来自 ServiceAccount Secret 中的、已更新的证书机构数据。
确保 coredns、kube-proxy 和其他使用集群内配置的 Pod 都正按预期方式工作。 将老的和新的 CA 都追加到 kube-apiserver 配置的 --client-ca-file 和 --kubelet-certificate-authority 标志所指的文件。
将老的和新的 CA 都追加到 kube-scheduler 配置的 --client-ca-file 标志所指的文件。
通过替换 client-certificate-data 和 client-key-data
中的内容,更新用户账号的证书。
有关为独立用户账号创建证书的更多信息,可参阅
为用户帐号配置证书 。
另外,还要更新 kubeconfig 文件中的 certificate-authority-data
节,使之包含 Base64 编码的老的和新的证书机构数据。
遵循下列步骤执行滚动更新
重新启动所有其他 被聚合的 API 服务器
或者 Webhook 处理程序 ,使之信任新的 CA 证书。
在所有节点上更新 kubelet 配置中的 clientCAFile 所指文件以及 kubelet.conf 中的
certificate-authority-data 并重启 kubelet 以同时使用老的和新的 CA 证书。
如果你的 kubelet 并未使用客户端证书轮换,则在所有节点上更新 kubelet.conf 中
client-certificate-data 和 client-key-data 以及 kubelet
客户端证书文件(通常位于 /var/lib/kubelet/pki 目录下)
使用用新的 CA 签名的证书
(apiserver.crt、apiserver-kubelet-client.crt 和 front-proxy-client.crt)
来重启 API 服务器。
你可以使用现有的私钥,也可以使用新的私钥。
如果你改变了私钥,则要将更新的私钥也放到 Kubernetes 证书目录下。
由于 Pod 既信任老的 CA 也信任新的 CA,Pod 中的客户端会经历短暂的连接断开状态,
之后再连接到使用新的 CA 所签名的证书的新的 API 服务器。
重启调度器以使用新的 CA 证书。 确保控制面组件的日志中没有 TLS 相关的错误信息。 为 Daemonset 和 Deployment 添加注解,从而触发较安全的滚动更新,替换 Pod。
示例:
for namespace in $( kubectl get namespace -o jsonpath = '{.items[*].metadata.name}' ) ; do
for name in $( kubectl get deployments -n $namespace -o jsonpath = '{.items[*].metadata.name}' ) ; do
kubectl patch deployment -n ${ namespace } ${ name } -p '{"spec":{"template":{"metadata":{"annotations":{"ca-rotation": "1"}}}}}' ;
done
for name in $( kubectl get daemonset -n $namespace -o jsonpath = '{.items[*].metadata.name}' ) ; do
kubectl patch daemonset -n ${ namespace } ${ name } -p '{"spec":{"template":{"metadata":{"annotations":{"ca-rotation": "1"}}}}}' ;
done
done
如果你的集群使用启动引导令牌来添加节点,则需要更新 kube-public 名字空间下的
ConfigMap cluster-info,使之包含新的 CA 证书。
base64_encoded_ca = " $( base64 -w0 /etc/kubernetes/pki/ca.crt) "
kubectl get cm/cluster-info --namespace kube-public -o yaml | \
/bin/sed "s/\(certificate-authority-data:\).*/\1 ${ base64_encoded_ca } /" | \
kubectl apply -f -
验证集群的功能正常
验证控制面组件的日志,以及 kubelet 和 kube-proxy 的日志,确保其中没有
抛出 TLS 错误,参阅
查看日志 .
验证被聚合的 API 服务器的日志,以及所有使用集群内配置的 Pod 的日志。
完成集群功能的检查之后:
更新所有的服务账号令牌,使之仅包含新的 CA 证书。
使用集群内 kubeconfig 的 Pod 最终也需要被重启,以获得新的服务账号 Secret
数据,进而不再信任老的 CA 证书。 从 kubeconfig 文件和 --client-ca-file 以及 --root-ca-file 标志所指向的文件
中去除老的 CA 数据,之后重启控制面组件。
重启 kubelet,移除 clientCAFile 标志所指向的文件以及 kubelet kubeconfig 文件中
的老的 CA 数据。
4.12.3 - 管理集群中的 TLS 认证 Kubernetes 提供 certificates.k8s.io API,可让你配置由你控制的证书颁发机构(CA)
签名的 TLS 证书。 你的工作负载可以使用这些 CA 和证书来建立信任。
certificates.k8s.io API使用的协议类似于
ACME 草案 。
说明: 使用 certificates.k8s.io API 创建的证书由指定 CA 颁发。将集群配置为使用集群根目录
CA 可以达到这个目的,但是你永远不要依赖这一假定。不要以为
这些证书将针对群根目录 CA 进行验证。
准备开始
你必须拥有一个 Kubernetes 的集群,同时你的 Kubernetes 集群必须带有 kubectl 命令行工具。
如果你还没有集群,你可以通过 Minikube 构建一
个你自己的集群,或者你可以使用下面任意一个 Kubernetes 工具构建:
要获知版本信息,请输入
kubectl version.
集群中的 TLS 信任 信任 Pod 中运行的应用程序所提供的 CA 通常需要一些额外的应用程序配置。
你需要将 CA 证书包添加到 TLS 客户端或服务器信任的 CA 证书列表中。
例如,你可以使用 Golang TLS 配置通过解析证书链并将解析的证书添加到
tls.Config 结构中的 RootCAs
字段中。
你可以用你的应用能够访问到的
ConfigMap
的形式来发布 CA 证书。
请求证书 以下部分演示如何为通过 DNS 访问的 Kubernetes 服务创建 TLS 证书。
说明: 本教程使用 CFSSL:Cloudflare's PKI 和 TLS 工具包
点击此处 了解更多信息。
下载并安装 CFSSL 本例中使用的 cfssl 工具可以在 github.com/cloudflare/cfssl/releases 下载。
创建证书签名请求 通过运行以下命令生成私钥和证书签名请求(或 CSR):
cat <<EOF | cfssl genkey - | cfssljson -bare server
{
"hosts": [
"my-svc.my-namespace.svc.cluster.local",
"my-pod.my-namespace.pod.cluster.local",
"192.0.2.24",
"10.0.34.2"
],
"CN": "system:node:my-pod.my-namespace.pod.cluster.local",
"key": {
"algo": "ecdsa",
"size": 256
},
"names": [
{
"O": "system:nodes"
}
]
}
EOF
其中 192.0.2.24 是服务的集群 IP,my-svc.my-namespace.svc.cluster.local
是服务的 DNS 名称,10.0.34.2 是 Pod 的 IP,而
my-pod.my-namespace.pod.cluster.local 是 Pod 的 DNS 名称。
你能看到以下的输出:
2017/03/21 06:48:17 [INFO] generate received request
2017/03/21 06:48:17 [INFO] received CSR
2017/03/21 06:48:17 [INFO] generating key: ecdsa-256
2017/03/21 06:48:17 [INFO] encoded CSR
此命令生成两个文件;它生成包含 PEM 编码
pkcs#10 证书请求的 server.csr,
以及 PEM 编码密钥的 server-key.pem,用于待生成的证书。
创建证书签名请求对象发送到 Kubernetes API 使用以下命令创建 CSR YAML 文件,并发送到 API 服务器:
cat <<EOF | kubectl apply -f -
apiVersion: certificates.k8s.io/v1
kind: CertificateSigningRequest
metadata:
name: my-svc.my-namespace
spec:
request: $(cat server.csr | base64 | tr -d '\n')
signerName: kubernetes.io/kubelet-serving
usages:
- digital signature
- key encipherment
- server auth
EOF
请注意,在步骤 1 中创建的 server.csr 文件是 base64 编码并存储在
.spec.request 字段中的。我们还要求提供 “digital signature(数字签名)”,
“密钥加密(key encipherment)” 和 “服务器身份验证(server auth)” 密钥用途,
由 kubernetes.io/kubelet-serving 签名程序签名的证书。
你也可以要求使用特定的 signerName。更多信息可参阅
支持的签署者名称 。
在 API server 中可以看到这些 CSR 处于 Pending 状态。执行下面的命令你将可以看到:
kubectl describe csr my-svc.my-namespace
Name: my-svc.my-namespace
Labels: <none>
Annotations: <none>
CreationTimestamp: Tue, 21 Mar 2017 07:03:51 -0700
Requesting User: yourname@example.com
Status: Pending
Subject:
Common Name: my-svc.my-namespace.svc.cluster.local
Serial Number:
Subject Alternative Names:
DNS Names: my-svc.my-namespace.svc.cluster.local
IP Addresses: 192.0.2.24
10.0.34.2
Events: <none>
批准证书签名请求 批准证书签名请求是通过自动批准过程完成的,或由集群管理员一次性完成。
有关这方面涉及的更多信息,请参见下文。
下载证书并使用它 CSR 被签署并获得批准后,你应该看到以下内容:
NAME AGE REQUESTOR CONDITION
my-svc.my-namespace 10m yourname@example.com Approved,Issued
你可以通过运行以下命令下载颁发的证书并将其保存到 server.crt 文件中:
kubectl get csr my-svc.my-namespace -o jsonpath = '{.status.certificate}' \
| base64 --decode > server.crt
现在你可以将 server.crt 和 server-key.pem 作为键值对来启动 HTTPS 服务器。
批准证书签名请求 Kubernetes 管理员(具有适当权限)可以使用 kubectl certificate approve 和
kubectl certificate deny 命令手动批准(或拒绝)证书签名请求。
但是,如果你打算大量使用此 API,则可以考虑编写自动化的证书控制器。
无论上述机器或人使用 kubectl,批准者的作用是验证 CSR 满足如下两个要求:
CSR 的 subject 控制用于签署 CSR 的私钥。这解决了伪装成授权主体的第三方的威胁。
在上述示例中,此步骤将验证该 Pod 控制了用于生成 CSR 的私钥。 CSR 的 subject 被授权在请求的上下文中执行。
这点用于处理不期望的主体被加入集群的威胁。
在上述示例中,此步骤将是验证该 Pod 是否被允许加入到所请求的服务中。 当且仅当满足这两个要求时,审批者应该批准 CSR,否则拒绝 CSR。
关于批准权限的警告 批准 CSR 的能力决定了群集中的信任关系。这也包括 Kubernetes API 所信任的人。
批准 CSR 的能力不能过于广泛和轻率。
在给予本许可之前,应充分了解上一节中提到的挑战和发布特定证书的后果。
给集群管理员的一个建议 本教程假设已经为 certificates API 配置了签名者。Kubernetes 控制器管理器
提供了一个签名者的默认实现。要启用它,请为控制器管理器设置
--cluster-signing-cert-file 和 --cluster-signing-key-file 参数,
使之取值为你的证书机构的密钥对的路径。
4.13 - 管理集群守护进程 执行 DaemonSet 管理的常见任务,例如执行滚动更新。
4.13.1 - 对 DaemonSet 执行滚动更新 本文介绍了如何对 DaemonSet 执行滚动更新。
准备开始 Kubernetes 1.6 或者更高版本中才支持 DaemonSet 滚动更新功能。 DaemonSet 更新策略 DaemonSet 有两种更新策略:
OnDelete: 使用 OnDelete 更新策略时,在更新 DaemonSet 模板后,只有当你手动删除老的
DaemonSet pods 之后,新的 DaemonSet Pod 才会 被自动创建。跟 Kubernetes 1.6 以前的版本类似。 RollingUpdate: 这是默认的更新策略。使用 RollingUpdate 更新策略时,在更新 DaemonSet 模板后,
老的 DaemonSet pods 将被终止,并且将以受控方式自动创建新的 DaemonSet pods。
更新期间,最多只能有 DaemonSet 的一个 Pod 运行于每个节点上。 执行滚动更新 要启用 DaemonSet 的滚动更新功能,必须设置 .spec.updateStrategy.type 为 RollingUpdate。
你可能想设置
.spec.updateStrategy.rollingUpdate.maxUnavailable (默认为 1) 和
.spec.minReadySeconds (默认为 0)。
创建带有 RollingUpdate 更新策略的 DaemonSet 下面的 YAML 包含一个 DaemonSet,其更新策略为 'RollingUpdate':
apiVersion : apps/v1
kind : DaemonSet
metadata :
name : fluentd-elasticsearch
namespace : kube-system
labels :
k8s-app : fluentd-logging
spec :
selector :
matchLabels :
name : fluentd-elasticsearch
updateStrategy :
type : RollingUpdate
rollingUpdate :
maxUnavailable : 1
template :
metadata :
labels :
name : fluentd-elasticsearch
spec :
tolerations :
# this toleration is to have the daemonset runnable on master nodes
# remove it if your masters can't run pods
- key : node-role.kubernetes.io/master
effect : NoSchedule
containers :
- name : fluentd-elasticsearch
image : quay.io/fluentd_elasticsearch/fluentd:v2.5.2
volumeMounts :
- name : varlog
mountPath : /var/log
- name : varlibdockercontainers
mountPath : /var/lib/docker/containers
readOnly : true
terminationGracePeriodSeconds : 30
volumes :
- name : varlog
hostPath :
path : /var/log
- name : varlibdockercontainers
hostPath :
path : /var/lib/docker/containers
检查了 DaemonSet 清单中更新策略的设置之后,创建 DaemonSet:
kubectl create -f https://k8s.io/examples/controllers/fluentd-daemonset.yaml
另一种方式是如果你希望使用 kubectl apply 来更新 DaemonSet 的话,也可以
使用 kubectl apply 来创建 DaemonSet:
kubectl apply -f https://k8s.io/examples/controllers/fluentd-daemonset.yaml
检查 DaemonSet 的滚动更新策略 首先,检查 DaemonSet 的更新策略,确保已经将其设置为 RollingUpdate:
kubectl get ds/fluentd-elasticsearch -o go-template= '{{.spec.updateStrategy.type}}{{"\n"}}' -n kube-system
如果还没在系统中创建 DaemonSet,请使用以下命令检查 DaemonSet 的清单:
kubectl apply -f https://k8s.io/examples/controllers/fluentd-daemonset.yaml --dry-run= client -o go-template= '{{.spec.updateStrategy.type}}{{"\n"}}'
两个命令的输出都应该为:
RollingUpdate
如果输出不是 RollingUpdate,请返回并相应地修改 DaemonSet 对象或者清单。
更新 DaemonSet 模板 对 RollingUpdate DaemonSet 的 .spec.template 的任何更新都将触发滚动更新。
这可以通过几个不同的 kubectl 命令来完成。
apiVersion : apps/v1
kind : DaemonSet
metadata :
name : fluentd-elasticsearch
namespace : kube-system
labels :
k8s-app : fluentd-logging
spec :
selector :
matchLabels :
name : fluentd-elasticsearch
updateStrategy :
type : RollingUpdate
rollingUpdate :
maxUnavailable : 1
template :
metadata :
labels :
name : fluentd-elasticsearch
spec :
tolerations :
# this toleration is to have the daemonset runnable on master nodes
# remove it if your masters can't run pods
- key : node-role.kubernetes.io/master
effect : NoSchedule
containers :
- name : fluentd-elasticsearch
image : quay.io/fluentd_elasticsearch/fluentd:v2.5.2
resources :
limits :
memory : 200Mi
requests :
cpu : 100m
memory : 200Mi
volumeMounts :
- name : varlog
mountPath : /var/log
- name : varlibdockercontainers
mountPath : /var/lib/docker/containers
readOnly : true
terminationGracePeriodSeconds : 30
volumes :
- name : varlog
hostPath :
path : /var/log
- name : varlibdockercontainers
hostPath :
path : /var/lib/docker/containers
声明式命令 如果你使用
配置文件
来更新 DaemonSet,请使用 kubectl apply:
kubectl apply -f https://k8s.io/examples/controllers/fluentd-daemonset-update.yaml
指令式命令 如果你使用
指令式命令
来更新 DaemonSets,请使用kubectl edit:
kubectl edit ds/fluentd-elasticsearch -n kube-system
只更新容器镜像 如果你只需要更新 DaemonSet 模板里的容器镜像,比如,.spec.template.spec.containers[*].image,
请使用 kubectl set image:
kubectl set image ds/fluentd-elasticsearch fluentd-elasticsearch= quay.io/fluentd_elasticsearch/fluentd:v2.6.0 -n kube-system
监视滚动更新状态 最后,观察 DaemonSet 最新滚动更新的进度:
kubectl rollout status ds/fluentd-elasticsearch -n kube-system
当滚动更新完成时,输出结果如下:
daemonset "fluentd-elasticsearch" successfully rolled out
故障排查 DaemonSet 滚动更新卡住 有时,DaemonSet 滚动更新可能卡住,以下是一些可能的原因:
一些节点可用资源耗尽 DaemonSet 滚动更新可能会卡住,其 Pod 至少在某个节点上无法调度运行。
当节点上可用资源耗尽 时,
这是可能的。
发生这种情况时,通过对 kubectl get nodes 和下面命令行的输出作比较,
找出没有调度部署 DaemonSet Pods 的节点:
kubectl get pods -l name = fluentd-elasticsearch -o wide -n kube-system
一旦找到这些节点,从节点上删除一些非 DaemonSet Pod,为新的 DaemonSet Pod 腾出空间。
不完整的滚动更新 如果最近的 DaemonSet 模板更新被破坏了,比如,容器处于崩溃循环状态或者容器镜像不存在
(通常由于拼写错误),就会发生 DaemonSet 滚动更新中断。
要解决此问题,只需再次更新 DaemonSet 模板即可。以前不健康的滚动更新不会阻止新的滚动更新。
时钟偏差 如果在 DaemonSet 中指定了 .spec.minReadySeconds,主控节点和工作节点之间的时钟偏差会使
DaemonSet 无法检测到正确的滚动更新进度。
清理 从名字空间中删除 DaemonSet:
kubectl delete ds fluentd-elasticsearch -n kube-system
接下来 4.13.2 - 对 DaemonSet 执行回滚 本文展示了如何对 DaemonSet 执行回滚。
准备开始
你必须拥有一个 Kubernetes 的集群,同时你的 Kubernetes 集群必须带有 kubectl 命令行工具。
如果你还没有集群,你可以通过 Minikube 构建一
个你自己的集群,或者你可以使用下面任意一个 Kubernetes 工具构建:
您的 Kubernetes 服务器版本必须不低于版本 1.7.
要获知版本信息,请输入
kubectl version.
你应该已经了解如何为 DaemonSet 执行滚东更新 。
对 DaemonSet 执行回滚 步骤 1:找到想要 DaemonSet 回滚到的历史修订版本(revision) 如果只想回滚到最后一个版本,可以跳过这一步。
列出 DaemonSet 的所有版本:
kubectl rollout history daemonset <daemonset-name>
此命令返回 DaemonSet 版本列表:
daemonsets "<daemonset-name>"
REVISION CHANGE-CAUSE
1 ...
2 ...
...
在创建时,DaemonSet 的变化原因从 kubernetes.io/change-cause 注解(annotation)
复制到其修订版本中。用户可以在 kubectl 命令中设置 --record=true,
将执行的命令记录在变化原因注解中。 执行以下命令,来查看指定版本的详细信息:
kubectl rollout history daemonset <daemonset-name> --revision= 1
该命令返回相应修订版本的详细信息:
daemonsets "<daemonset-name>" with revision #1
Pod Template:
Labels: foo = bar
Containers:
app:
Image: ...
Port: ...
Environment: ...
Mounts: ...
Volumes: ...
步骤 2:回滚到指定版本 # 在 --to-revision 中指定你从步骤 1 中获取的修订版本
kubectl rollout undo daemonset <daemonset-name> --to-revision= <revision>
如果成功,命令会返回:
daemonset "<daemonset-name>" rolled back
说明: 如果 --to-revision 参数未指定,将选中最近的版本。
步骤 3:监视 DaemonSet 回滚进度 kubectl rollout undo daemonset 向服务器表明启动 DaemonSet 回滚。
真正的回滚是在集群的
控制面
异步完成的。
执行以下命令,来监视 DaemonSet 回滚进度:
kubectl rollout status ds/<daemonset-name>
回滚完成时,输出形如:
daemonset "<daemonset-name>" successfully rolled out
理解 DaemonSet 修订版本 在前面的 kubectl rollout history 步骤中,你获得了一个修订版本列表,每个修订版本都存储在名为
ControllerRevision 的资源中。
要查看每个修订版本中保存的内容,可以找到 DaemonSet 修订版本的原生资源:
kubectl get controllerrevision -l <daemonset-selector-key>= <daemonset-selector-value>
该命令返回 ControllerRevisions 列表:
NAME CONTROLLER REVISION AGE
<daemonset-name>-<revision-hash> DaemonSet/<daemonset-name> 1 1h
<daemonset-name>-<revision-hash> DaemonSet/<daemonset-name> 2 1h
每个 ControllerRevision 中存储了相应 DaemonSet 版本的注解和模板。
kubectl rollout undo 选择特定的 ControllerRevision,并用
ControllerRevision 中存储的模板代替 DaemonSet 的模板。
kubectl rollout undo 相当于通过其他命令(如 kubectl edit 或 kubectl apply)
将 DaemonSet 模板更新至先前的版本。
说明: 注意 DaemonSet 修订版本只会正向变化。也就是说,回滚完成后,所回滚到的
ControllerRevision 版本号 (.revision 字段) 会增加。
例如,如果用户在系统中有版本 1 和版本 2,并从版本 2 回滚到版本 1,
带有 .revision: 1 的ControllerRevision 将变为 .revision: 3。
故障排查 4.14 - 安装服务目录 安装服务目录扩展 API。
4.14.1 - 使用 Helm 安装 Service Catalog
服务目录(Service Catalog)是 服务目录是一种扩展 API,它能让 Kubernetes 集群中运行的应用易于使用外部托管的的软件服务,例如云供应商提供的数据仓库服务。
服务目录可以检索、供应、和绑定由 服务代理人(Service Brokers)
提供的外部托管服务(Managed Services) ,
而无需知道那些服务具体是怎样创建和托管的。
使用 Helm 在 Kubernetes 集群上安装 Service Catalog。
要获取有关此过程的最新信息,请浏览 kubernetes-incubator/service-catalog 仓库。
准备开始 理解服务目录 的关键概念。 Service Catalog 需要 Kubernetes 集群版本在 1.7 或更高版本。 你必须启用 Kubernetes 集群的 DNS 功能。如果使用基于云的 Kubernetes 集群或 Minikube ,则可能已经启用了集群 DNS。 如果你正在使用 hack/local-up-cluster.sh,请确保设置了 KUBE_ENABLE_CLUSTER_DNS 环境变量,然后运行安装脚本。 安装和设置 v1.7 或更高版本的 kubectl ,确保将其配置为连接到 Kubernetes 集群。安装 v2.7.0 或更高版本的 Helm 。遵照 Helm 安装说明 。 如果已经安装了适当版本的 Helm,请执行 helm init 来安装 Helm 的服务器端组件 Tiller。 添加 service-catalog Helm 仓库 安装 Helm 后,通过执行以下命令将 service-catalog Helm 存储库添加到本地计算机:
helm repo add svc-cat https://svc-catalog-charts.storage.googleapis.com
通过执行以下命令进行检查,以确保安装成功:
helm search service-catalog
如果安装成功,该命令应输出以下内容:
NAME VERSION DESCRIPTION
svc-cat/catalog 0.0.1 service-catalog API server and controller-manag...
启用 RBAC 你的 Kubernetes 集群必须启用 RBAC,这需要你的 Tiller Pod 具有 cluster-admin 访问权限。
如果你使用的是 Minikube,请使用以下参数运行 minikube start 命令:
minikube start --extra-config= apiserver.Authorization.Mode= RBAC
如果你使用 hack/local-up-cluster.sh,请使用以下值设置 AUTHORIZATION_MODE 环境变量:
AUTHORIZATION_MODE=Node,RBAC hack/local-up-cluster.sh -O
默认情况下,helm init 将 Tiller Pod 安装到 kube-system 命名空间,Tiller 配置为使用 default 服务帐户。
说明: 如果在运行 helm init 时使用了 --tiller-namespace 或 --service-account 参数,
则需要调整以下命令中的 --serviceaccount 参数以引用相应的名字空间和服务账号名称。
配置 Tiller 以获得 cluster-admin 访问权限:
kubectl create clusterrolebinding tiller-cluster-admin \
--clusterrole= cluster-admin \
--serviceaccount= kube-system:default
在 Kubernetes 集群中安装 Service Catalog 使用以下命令从 Helm 存储库的根目录安装 Service Catalog:
helm install catalog svc-cat/catalog --namespace catalog
helm install svc-cat/catalog --name catalog --namespace catalog
接下来 4.14.2 - 使用 SC 安装服务目录
服务目录(Service Catalog)是 服务目录是一种扩展 API,它能让 Kubernetes 集群中运行的应用易于使用外部托管的的软件服务,例如云供应商提供的数据仓库服务。
服务目录可以检索、供应、和绑定由 服务代理人(Service Brokers)
提供的外部托管服务(Managed Services) ,
而无需知道那些服务具体是怎样创建和托管的。
使用服务目录安装程序
工具可以轻松地在 Kubernetes 集群上安装或卸载服务目录。
这个 CLI 工具以 sc 命令形式被安装在您的本地环境中。
准备开始 了解服务目录
的主要概念。
安装 Go 1.6+ 以及设置 GOPATH。
安装生成 SSL 工件所需的 cfssl 工具。
服务目录需要 Kubernetes 1.7+ 版本。
安装和设置 kubectl ,
以便将其配置为连接到 Kubernetes v1.7+ 集群。
要安装服务目录,kubectl 用户必须绑定到 cluster-admin 角色。
为了确保这是正确的,请运行以下命令:
kubectl create clusterrolebinding cluster-admin-binding --clusterrole= cluster-admin --user= <user-name>
在本地环境中安装 sc 使用 go get 命令安装 sc CLI 工具:
go get github.com/ GoogleCloudPlatform/ k8s- service- catalog/ installer/ cmd/ sc
执行上述命令后,sc 应被安装在 GOPATH/bin 目录中了。
在 Kubernetes 集群中安装服务目录 首先,检查是否已经安装了所有依赖项。运行:
如检查通过,应输出:
Dependency check passed. You are good to go.
接下来,运行安装命令并指定要用于备份的 storageclass:
sc install --etcd-backup-storageclass "standard"
卸载服务目录 如果您想使用 sc 工具从 Kubernetes 集群卸载服务目录,请运行:
接下来 4.15.1 - 验证 IPv4/IPv6 双协议栈 本文分享了如何验证 IPv4/IPv6 双协议栈的 Kubernetes 集群。
准备开始 提供程序对双协议栈网络的支持 (云供应商或其他方式必须能够为 Kubernetes 节点
提供可路由的 IPv4/IPv6 网络接口) 一个能够支持双协议栈的
网络插件 ,
(如 kubenet 或 Calico)。 启用双协议栈 集群验证寻址 验证节点寻址 每个双协议栈节点应分配一个 IPv4 块和一个 IPv6 块。
通过运行以下命令来验证是否配置了 IPv4/IPv6 Pod 地址范围。
将示例节点名称替换为集群中的有效双协议栈节点。
在此示例中,节点的名称为 k8s-linuxpool1-34450317-0:
kubectl get nodes k8s-linuxpool1-34450317-0 -o go-template --template= '{{range .spec.podCIDRs}}{{printf "%s\n" .}}{{end}}'
10.244.1.0/24
a00:100::/24
应该分配一个 IPv4 块和一个 IPv6 块。
验证节点是否检测到 IPv4 和 IPv6 接口(用集群中的有效节点替换节点名称。
在此示例中,节点名称为 k8s-linuxpool1-34450317-0):
kubectl get nodes k8s-linuxpool1-34450317-0 -o go-template --template= '{{range .status.addresses}}{{printf "%s: %s \n" .type .address}}{{end}}'
Hostname: k8s-linuxpool1-34450317-0
InternalIP: 10.240.0.5
InternalIP: 2001:1234:5678:9abc::5
验证 Pod 寻址 验证 Pod 已分配了 IPv4 和 IPv6 地址。(用集群中的有效 Pod 替换 Pod 名称。
在此示例中,Pod 名称为 pod01)
kubectl get pods pod01 -o go-template --template= '{{range .status.podIPs}}{{printf "%s \n" .ip}}{{end}}'
10.244.1.4
a00:100::4
你也可以通过 status.podIPs 使用 Downward API 验证 Pod IP。
以下代码段演示了如何通过容器内称为 MY_POD_IPS 的环境变量公开 Pod 的 IP 地址。
env :
- name : MY_POD_IPS
valueFrom :
fieldRef :
fieldPath : status.podIPs
使用以下命令打印出容器内部 MY_POD_IPS 环境变量的值。
该值是一个逗号分隔的列表,与 Pod 的 IPv4 和 IPv6 地址相对应。
kubectl exec -it pod01 -- set | grep MY_POD_IPS
MY_POD_IPS=10.244.1.4,a00:100::4
Pod 的 IP 地址也将被写入容器内的 /etc/hosts 文件中。
在双栈 Pod 上执行 cat /etc/hosts 命令操作。
从输出结果中,你可以验证 Pod 的 IPv4 和 IPv6 地址。
kubectl exec -it pod01 -- cat /etc/hosts
# Kubernetes-managed hosts file.
127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
fe00::0 ip6-mcastprefix
fe00::1 ip6-allnodes
fe00::2 ip6-allrouters
10.244.1.4 pod01
a00:100::4 pod01
验证服务 创建以下未显式定义 .spec.ipFamilyPolicy 的 Service。
Kubernetes 将从首个配置的 service-cluster-ip-range 给 Service 分配集群 IP,
并将 .spec.ipFamilyPolicy 设置为 SingleStack。
apiVersion : v1
kind : Service
metadata :
name : my-service
labels :
app : MyApp
spec :
selector :
app : MyApp
ports :
- protocol : TCP
port : 80
使用 kubectl 查看 Service 的 YAML 定义。
kubectl get svc my-service -o yaml
该 Service 通过在 kube-controller-manager 的 --service-cluster-ip-range
标志设置的第一个配置范围,将 .spec.ipFamilyPolicy 设置为 SingleStack,
将 .spec.clusterIP 设置为 IPv4 地址。
apiVersion : v1
kind : Service
metadata :
name : my-service
namespace : default
spec :
clusterIP : 10.0.217.164
clusterIPs :
- 10.0.217.164
ipFamilies :
- IPv4
ipFamilyPolicy : SingleStack
ports :
- port : 80
protocol : TCP
targetPort : 9376
selector :
app : MyApp
sessionAffinity : None
type : ClusterIP
status :
loadBalancer : {}
创建以下显示定义 .spec.ipFamilies 数组中的第一个元素为 IPv6 的 Service。
Kubernetes 将 service-cluster-ip-range 配置的 IPv6 地址范围给 Service 分配集群 IP,
并将 .spec.ipFamilyPolicy 设置为 SingleStack。
apiVersion : v1
kind : Service
metadata :
name : my-service
spec :
ipFamily : IPv6
selector :
app : MyApp
ports :
- protocol : TCP
port : 80
targetPort : 9376 使用 kubectl 查看 Service 的 YAML 定义。
kubectl get svc my-service -o yaml
该 Service 通过在 kube-controller-manager 的 --service-cluster-ip-range
标志设置的 IPv6 地址范围,将 .spec.ipFamilyPolicy 设置为 SingleStack,
将 .spec.clusterIP 设置为 IPv6 地址。
apiVersion : v1
kind : Service
metadata :
labels :
app : MyApp
name : my-service
spec :
clusterIP : fd00::5118
clusterIPs :
- fd00::5118
ipFamilies :
- IPv6
ipFamilyPolicy : SingleStack
ports :
- port : 80
protocol : TCP
targetPort : 80
selector :
app : MyApp
sessionAffinity : None
type : ClusterIP
status :
loadBalancer : {}
创建以下显式定义 .spec.ipFamilyPolicy 为 PreferDualStack 的 Service。
Kubernetes 将分配 IPv4 和 IPv6 地址(因为该集群启用了双栈),
并根据 .spec.ipFamilies 数组中第一个元素的地址族,
从 .spec.ClusterIPs 列表中选择 .spec.ClusterIP。
apiVersion : v1
kind : Service
metadata :
name : my-service
labels :
app : MyApp
spec :
ipFamilyPolicy : PreferDualStack
selector :
app : MyApp
ports :
- protocol : TCP
port : 80
说明: kubectl get svc 命令将仅在 CLUSTER-IP 字段中显示主 IP。
kubectl get svc -l app = MyApp
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT( S) AGE
my-service ClusterIP fe80:20d::d06b <none> 80/TCP 9s
使用 kubectl describe 验证服务是否从 IPv4 和 IPv6 地址块中获取了集群 IP。
然后你就可以通过 IP 和端口,验证对服务的访问。
kubectl describe svc -l app = MyApp
Name: my-service
Namespace: default
Labels: app=MyApp
Annotations: <none>
Selector: app=MyApp
Type: ClusterIP
IP Family Policy: PreferDualStack
IP Families: IPv4,IPv6
IP: 10.0.216.242
IPs: 10.0.216.242,fd00::af55
Port: <unset> 80/TCP
TargetPort: 9376/TCP
Endpoints: <none>
Session Affinity: None
Events: <none>
创建双协议栈负载均衡服务 如果云提供商支持配置启用 IPv6 的外部负载均衡器,则将 ipFamily 字段设置为
IPv6 并将 type 字段设置为 LoadBalancer 的方式创建以下服务:
apiVersion : v1
kind : Service
metadata :
name : my-service
labels :
app : MyApp
spec :
ipFamily : IPv6
type : LoadBalancer
selector :
app : MyApp
ports :
- protocol : TCP
port : 80
targetPort : 9376 验证服务是否从 IPv6 地址块中接收到 CLUSTER-IP 地址以及 EXTERNAL-IP。
然后,你可以通过 IP 和端口验证对服务的访问。
kubectl get svc -l app = MyApp
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
my-service ClusterIP fe80:20d::d06b 2001:db8:f100:4002::9d37:c0d7 80:31868/TCP 30s
4.16 - 用插件扩展 kubectl 通过创建和安装 kubectl 插件扩展 kubectl。
本指南演示了如何为 kubectl 安装和编写扩展。
通过将核心 kubectl 命令看作与 Kubernetes 集群交互的基本构建块,
集群管理员可以将插件视为一种利用这些构建块创建更复杂行为的方法。
插件用新的子命令扩展了 kubectl,允许新的和自定义的特性不包括在 kubectl 的主要发行版中。
准备开始 你需要安装一个可用的 kubectl 可执行文件。
安装 kubectl 插件 插件只不过是一个独立的可执行文件,名称以 kubectl- 开头。
要安装插件,只需将此可执行文件移动到 PATH 中的任何位置。
你也可以使用 Krew 来发现和安装开源的 kubectl 插件。
Krew 是一个由 Kubernetes SIG CLI 社区维护的插件管理器。
注意: Krew
插件索引 所维护的 kubectl 插件并未经过安全性审查。
你要了解安装和运行第三方插件的安全风险,因为它们本质上时是一些在你的机器上
运行的程序。
发现插件 kubectl 提供一个命令 kubectl plugin list,用于搜索路径查找有效的插件可执行文件。
执行此命令将遍历路径中的所有文件。任何以 kubectl- 开头的可执行文件都将在这个命令的输出中以它们在路径中出现的顺序显示。
任何以 kubectl- 开头的文件如果不可执行,都将包含一个警告。
对于任何相同的有效插件文件,都将包含一个警告。
你可以使用 Krew 从社区策划的插件索引
中发现和安装 kubectl 插件。
限制 目前无法创建覆盖现有 kubectl 命令的插件。
例如,创建一个插件 kubectl-version 将导致该插件永远不会被执行,
因为现有的 kubectl version 命令总是优先于它执行。
由于这个限制,也不可能使用插件将新的子命令添加到现有的 kubectl 命令中。
例如,通过将插件命名为 kubectl-create-foo 来添加子命令 kubectl create foo 将导致该插件被忽略。
对于任何试图这样做的有效插件 kubectl plugin list 的输出中将显示警告。
编写 kubectl 插件 你可以用任何编程语言或脚本编写插件,允许你编写命令行命令。
不需要安装插件或预加载,插件可执行程序从 kubectl 二进制文件接收继承的环境,
插件根据其名称确定它希望实现的命令路径。
例如,一个插件想要提供一个新的命令 kubectl foo,它将被简单地命名为 kubectl-foo,
并且位于用户 PATH 的某个位置。
示例插件 #!/bin/bash
# 可选的参数处理
if [[ "$1" == "version" ]]
then
echo "1.0.0"
exit 0
fi
# 可选的参数处理
if [[ "$1" == "config" ]]
then
echo $KUBECONFIG
exit 0
fi
echo "I am a plugin named kubectl-foo"
使用插件 要使用上面的插件,只需使其可执行:
sudo chmod +x ./kubectl-foo
并将它放在你的 PATH 中的任何地方:
sudo mv ./kubectl-foo /usr/local/bin
你现在可以调用你的插件作为 kubectl 命令:
kubectl foo
I am a plugin named kubectl-foo
所有参数和标记按原样传递给可执行文件:
kubectl foo version
1.0.0
所有环境变量也按原样传递给可执行文件:
export KUBECONFIG = ~/.kube/config
kubectl foo config
/home/<user>/.kube/config
KUBECONFIG = /etc/kube/config kubectl foo config
/etc/kube/config
此外,传递给插件的第一个参数总是调用它的位置的绝对路径(在上面的例子中,$0 将等于 /usr/local/bin/kubectl-foo)。
命名插件 如上面的例子所示,插件根据文件名确定要实现的命令路径,插件所针对的命令路径中的每个子命令都由破折号(-)分隔。
例如,当用户调用命令 kubectl foo bar baz 时,希望调用该命令的插件的文件名为 kubectl-foo-bar-baz。
参数和标记处理 说明: 插件机制不会为插件进程创建任何定制的、特定于插件的值或环境变量。
较老的插件机制会提供环境变量(例如 KUBECTL_PLUGINS_CURRENT_NAMESPACE);这种机制已被废弃。
kubectl 插件必须解析并检查传递给它们的所有参数。
参阅使用命令行运行时包 了解针对
插件开发人员的 Go 库的细节。
这里是一些用户调用你的插件的时候提供额外标志和参数的场景。
这些场景时基于上述案例中的 kubectl-foo-bar-baz 插件的。
如果你运行 kubectl foo bar baz arg1 --flag=value arg2,kubectl 的插件机制将首先尝试找到
最长可能名称的插件,在本例中是 kubectl-foo-bar-baz-arg1。
当没有找到这个插件时,kubectl 就会将最后一个以破折号分隔的值视为参数(在本例中为 arg1),
并尝试找到下一个最长的名称 kubectl-foo-bar-baz。
在找到具有此名称的插件后,它将调用该插件,并在其名称之后将所有参数和标志传递给插件进程。
示例:
# 创建一个插件
echo -e '#!/bin/bash\n\necho "My first command-line argument was $1"' > kubectl-foo-bar-baz
sudo chmod +x ./kubectl-foo-bar-baz
# 将插件放到 PATH 下完成"安装"
sudo mv ./kubectl-foo-bar-baz /usr/local/bin
# 确保 kubectl 能够识别我们的插件
kubectl plugin list
The following kubectl-compatible plugins are available:
/usr/local/bin/kubectl-foo-bar-baz
# 测试通过 "kubectl" 命令来调用我们的插件时可行的
# 即使我们给插件传递一些额外的参数或标志
kubectl foo bar baz arg1 --meaningless-flag= true
My first command-line argument was arg1
正如你所看到的,我们的插件是基于用户指定的 kubectl 命令找到的,
所有额外的参数和标记都是按原样传递给插件可执行文件的。
带有破折号和下划线的名称 虽然 kubectl 插件机制在插件文件名中使用破折号(-)分隔插件处理的子命令序列,
但是仍然可以通过在文件名中使用下划线(_)来创建命令行中包含破折号的插件命令。
例子:
# 创建文件名中包含下划线的插件
echo -e '#!/bin/bash\n\necho "I am a plugin with a dash in my name"' > ./kubectl-foo_bar
sudo chmod +x ./kubectl-foo_bar
# 将插件放到 PATH 下
sudo mv ./kubectl-foo_bar /usr/local/bin
# 现在可以通过 kubectl 来调用插件
kubectl foo-bar
I am a plugin with a dash in my name
请注意,在插件文件名中引入下划线并不会阻止我们使用 kubectl foo_bar 之类的命令。
可以使用破折号(-)或下划线(_)调用上面示例中的命令:
# 我们的插件也可以用破折号来调用
kubectl foo-bar
I am a plugin with a dash in my name
# 你也可以使用下划线来调用我们的定制命令
kubectl foo_bar
I am a plugin with a dash in my name
命名冲突和弊端 可以在 PATH 的不同位置提供多个文件名相同的插件,
例如,给定一个 PATH 为: PATH=/usr/local/bin/plugins:/usr/local/bin/moreplugins,
在 /usr/local/bin/plugins 和 /usr/local/bin/moreplugins 中可以存在一个插件
kubectl-foo 的副本,这样 kubectl plugin list 命令的输出就是:
PATH = /usr/local/bin/plugins:/usr/local/bin/moreplugins kubectl plugin list
The following kubectl-compatible plugins are available:
/usr/local/bin/plugins/kubectl-foo
/usr/local/bin/moreplugins/kubectl-foo
- warning: /usr/local/bin/moreplugins/kubectl-foo is overshadowed by a similarly named plugin: /usr/local/bin/plugins/kubectl-foo
error: one plugin warning was found
在上面的场景中 /usr/local/bin/moreplugins/kubectl-foo 下的警告告诉我们这个插件永远不会被执行。
相反,首先出现在我们路径中的可执行文件 /usr/local/bin/plugins/kubectl-foo
总是首先被 kubectl 插件机制找到并执行。
解决这个问题的一种方法是你确保你希望与 kubectl 一起使用的插件的位置总是在你的路径中首先出现。
例如,如果我们总是想使用 /usr/local/bin/moreplugins/kubectl foo,
那么在调用 kubectl 命令 kubectl foo 时,我们只需将路径的值更改为 PATH=/usr/local/bin/moreplugins:/usr/local/bin/plugins。
调用最长的可执行文件名 对于插件文件名而言还有另一种弊端,给定用户路径中的两个插件 kubectl-foo-bar 和 kubectl-foo-bar-baz
kubectl 插件机制总是为给定的用户命令选择尽可能长的插件名称。下面的一些例子进一步的说明了这一点:
# 对于给定的 kubectl 命令,最长可能文件名的插件是被优先选择的
kubectl foo bar baz
Plugin kubectl-foo-bar-baz is executed
Plugin kubectl-foo-bar is executed
Plugin kubectl-foo-bar-baz is executed, with "buz" as its first argument
Plugin kubectl-foo-bar is executed, with "buz" as its first argument
这种设计选择确保插件子命令可以跨多个文件实现,如果需要,这些子命令可以嵌套在"父"插件命令下:
kubectl-parent
kubectl-parent-subcommand
kubectl-parent-subcommand-subsubcommand
检查插件警告 你可以使用前面提到的 kubectl plugin list 命令来确保你的插件可以被 kubectl 看到,
并且验证没有警告防止它被称为 kubectl 命令。
The following kubectl-compatible plugins are available:
test/fixtures/pkg/kubectl/plugins/kubectl-foo
/usr/local/bin/kubectl-foo
- warning: /usr/local/bin/kubectl-foo is overshadowed by a similarly named plugin: test/fixtures/pkg/kubectl/plugins/kubectl-foo
plugins/kubectl-invalid
- warning: plugins/kubectl-invalid identified as a kubectl plugin, but it is not executable
error: 2 plugin warnings were found
使用命令行运行时包 如果你在编写 kubectl 插件,而且你选择使用 Go 语言,你可以利用
cli-runtime 工具库。
这些库提供了一些辅助函数,用来解析和更新用户的
kubeconfig
文件,向 API 服务器发起 REST 风格的请求,或者将参数绑定到某配置上,
抑或将其打印输出。
关于 CLI Runtime 仓库所提供的工具的使用实例,可参考
CLI 插件示例 项目。
分发 kubectl 插件 如果你开发了一个插件给别人使用,你应该考虑如何为其封装打包、如何分发软件
以及将来的更新到用户。
Krew Krew 提供了一种对插件进行打包和分发的跨平台方式。
基于这种方式,你会在所有的目标平台(Linux、Windows、macOS 等)使用同一
种打包形式,包括为用户提供更新。
Krew 也维护一个插件索引(plugin index)
以便其他人能够发现你的插件并安装之。
原生的与特定平台的包管理 另一种方式是,你可以使用传统的包管理器(例如 Linux 上 的 apt 或 yum,
Windows 上的 Chocolatey、macOs 上的 Homebrew)。
只要能够将新的可执行文件放到用户的 PATH 路径上某处,这种包管理器就符合需要。
作为一个插件作者,如果你选择这种方式来分发,你就需要自己来管理和更新
你的 kubectl 插件的分发包,包括所有平台和所有发行版本。
源代码 你也可以发布你的源代码,例如,发布为某个 Git 仓库。
如果你选择这条路线,希望使用该插件的用户必须取回代码、配置一个构造环境
(如果需要编译的话)并部署该插件。
如果你也提供编译后的软件包,或者使用 Krew,那就会大大简化安装过程了。
接下来 查看 CLI 插件库示例,查看用 Go 编写的插件的详细示例 如有任何问题,请随时联系 SIG CLI 了解 Krew ,一个 kubectl 插件管理器。 4.17 - 管理巨页(HugePages) 将大页配置和管理为集群中的可调度资源。
FEATURE STATE: Kubernetes v1.20 [stable]
Kubernetes 支持在 Pod 应用中使用预先分配的巨页。本文描述了用户如何使用巨页,以及当前的限制。
准备开始 为了使节点能够上报巨页容量,Kubernetes 节点必须预先分配巨页。每个节点只能预先分配一种特定规格的巨页。 节点会自动发现全部巨页资源,并作为可供调度的资源进行上报。
API 用户可以通过在容器级别的资源需求中使用资源名称 hugepages-<size> 来使用巨页,其中的 size 是特定节点上支持的以整数值表示的最小二进制单位。 例如,如果一个节点支持 2048KiB 和 1048576KiB 页面大小,它将公开可调度的资源 hugepages-2Mi 和 hugepages-1Gi。与 CPU 或内存不同,巨页不支持过量使用(overcommit)。注意,在请求巨页资源时,还必须请求内存或 CPU 资源。
同一 Pod 的 spec 中可能会消耗不同尺寸的巨页。在这种情况下,它必须对所有挂载卷使用 medium: HugePages-<hugepagesize> 标识。
apiVersion : v1
kind : Pod
metadata :
name : huge-pages-example
spec :
containers :
- name : example
image : fedora:latest
command :
- sleep
- inf
volumeMounts :
- mountPath : /hugepages-2Mi
name : hugepage-2mi
- mountPath : /hugepages-1Gi
name : hugepage-1gi
resources :
limits :
hugepages-2Mi : 100Mi
hugepages-1Gi : 2Gi
memory : 100Mi
requests :
memory : 100Mi
volumes :
- name : hugepage-2mi
emptyDir :
medium : HugePages-2Mi
- name : hugepage-1gi
emptyDir :
medium : HugePages-1Gi
Pod 只有在请求同一大小的巨页时才使用 medium:HugePages。
apiVersion : v1
kind : Pod
metadata :
name : huge-pages-example
spec :
containers :
- name : example
image : fedora:latest
command :
- sleep
- inf
volumeMounts :
- mountPath : /hugepages
name : hugepage
resources :
limits :
hugepages-2Mi : 100Mi
memory : 100Mi
requests :
memory : 100Mi
volumes :
- name : hugepage
emptyDir :
medium : HugePages
巨页的资源请求值必须等于其限制值。该条件在指定了资源限制,而没有指定请求的情况下默认成立。 巨页是被隔离在 pod 作用域的,因此每个容器在 spec 中都对 cgroup 沙盒有自己的限制。 巨页可用于 EmptyDir 卷,不过 EmptyDir 卷所使用的巨页数量不能够超出 Pod 请求的巨页数量。 通过带有 SHM_HUGETLB 的 shmget() 使用巨页的应用,必须运行在一个与
proc/sys/vm/hugetlb_shm_group 匹配的补充组下。 通过 ResourceQuota 资源,可以使用 hugepages-<size> 标记控制每个命名空间下的巨页使用量,
类似于使用 cpu 或 memory 来控制其他计算资源。 多种尺寸的巨页的支持需要特性门控配置。它可以通过 HugePageStorageMediumSize 特性门控 在 kubelet 和 kube-apiserver 中开启(--feature-gates=HugePageStorageMediumSize=false)。 4.18 - 调度 GPUs 配置和调度 GPU 成一类资源以供集群中节点使用。
FEATURE STATE: Kubernetes v1.10 [beta]
Kubernetes 支持对节点上的 AMD 和 NVIDIA GPU (图形处理单元)进行管理,目前处于实验 状态。
本页介绍用户如何在不同的 Kubernetes 版本中使用 GPU,以及当前存在的一些限制。
使用设备插件 Kubernetes 实现了设备插件(Device Plugins)
以允许 Pod 访问类似 GPU 这类特殊的硬件功能特性。
作为集群管理员,你要在节点上安装来自对应硬件厂商的 GPU 驱动程序,并运行
来自 GPU 厂商的对应的设备插件。
当以上条件满足时,Kubernetes 将暴露 amd.com/gpu 或 nvidia.com/gpu 为
可调度的资源。
你可以通过请求 <vendor>.com/gpu 资源来使用 GPU 设备,就像你为 CPU
和内存所做的那样。
不过,使用 GPU 时,在如何指定资源需求这个方面还是有一些限制的:
GPUs 只能设置在 limits 部分,这意味着:你可以指定 GPU 的 limits 而不指定其 requests,Kubernetes 将使用限制
值作为默认的请求值; 你可以同时指定 limits 和 requests,不过这两个值必须相等。 你不可以仅指定 requests 而不指定 limits。 容器(以及 Pod)之间是不共享 GPU 的。GPU 也不可以过量分配(Overcommitting)。 每个容器可以请求一个或者多个 GPU,但是用小数值来请求部分 GPU 是不允许的。 apiVersion : v1
kind : Pod
metadata :
name : cuda-vector-add
spec :
restartPolicy : OnFailure
containers :
- name : cuda-vector-add
# https://github.com/kubernetes/kubernetes/blob/v1.7.11/test/images/nvidia-cuda/Dockerfile
image : "k8s.gcr.io/cuda-vector-add:v0.1"
resources :
limits :
nvidia.com/gpu : 1 # requesting 1 GPU
部署 AMD GPU 设备插件 官方的 AMD GPU 设备插件 有以下要求:
Kubernetes 节点必须预先安装 AMD GPU 的 Linux 驱动。 如果你的集群已经启动并且满足上述要求的话,可以这样部署 AMD 设备插件:
kubectl create -f https://raw.githubusercontent.com/RadeonOpenCompute/k8s-device-plugin/r1.10/k8s-ds-amdgpu-dp.yaml
你可以到 RadeonOpenCompute/k8s-device-plugin
项目报告有关此设备插件的问题。
部署 NVIDIA GPU 设备插件 对于 NVIDIA GPUs,目前存在两种设备插件的实现:
官方的 NVIDIA GPU 设备插件 官方的 NVIDIA GPU 设备插件 有以下要求:
Kubernetes 的节点必须预先安装了 NVIDIA 驱动 Kubernetes 的节点必须预先安装 nvidia-docker 2.0 Docker 的默认运行时 必须设置为 nvidia-container-runtime,而不是 runc NVIDIA 驱动版本 ~= 384.81 如果你的集群已经启动并且满足上述要求的话,可以这样部署 NVIDIA 设备插件:
kubectl create -f https://raw.githubusercontent.com/NVIDIA/k8s-device-plugin/1.0.0-beta4/nvidia-device-plugin.yml
请到 NVIDIA/k8s-device-plugin 项目报告有关此设备插件的问题。
GCE 中使用的 NVIDIA GPU 设备插件 GCE 使用的 NVIDIA GPU 设备插件 并不要求使用 nvidia-docker,并且对于任何实现了 Kubernetes CRI 的容器运行时,都应该能够使用。这一实现已经在 Container-Optimized OS 上进行了测试,并且在 1.9 版本之后会有对于 Ubuntu 的实验性代码。
你可以使用下面的命令来安装 NVIDIA 驱动以及设备插件:
# 在 COntainer-Optimized OS 上安装 NVIDIA 驱动:
kubectl create -f https://raw.githubusercontent.com/GoogleCloudPlatform/container-engine-accelerators/stable/daemonset.yaml
# 在 Ubuntu 上安装 NVIDIA 驱动 (实验性质):
kubectl create -f https://raw.githubusercontent.com/GoogleCloudPlatform/container-engine-accelerators/stable/nvidia-driver-installer/ubuntu/daemonset.yaml
# 安装设备插件:
kubectl create -f https://raw.githubusercontent.com/kubernetes/kubernetes/release-1.12/cluster/addons/device-plugins/nvidia-gpu/daemonset.yaml
请到 GoogleCloudPlatform/container-engine-accelerators 报告有关此设备插件以及安装方法的问题。
关于如何在 GKE 上使用 NVIDIA GPUs,Google 也提供自己的指令 。
集群内存在不同类型的 GPU 如果集群内部的不同节点上有不同类型的 NVIDIA GPU,那么你可以使用
节点标签和节点选择器
来将 pod 调度到合适的节点上。
例如:
# 为你的节点加上它们所拥有的加速器类型的标签
kubectl label nodes <node-with-k80> accelerator = nvidia-tesla-k80
kubectl label nodes <node-with-p100> accelerator = nvidia-tesla-p100
自动节点标签 如果你在使用 AMD GPUs,你可以部署
Node Labeller ,
它是一个 控制器 ,
会自动给节点打上 GPU 属性标签。目前支持的属性:
设备 ID (-device-id) VRAM 大小 (-vram) SIMD 数量(-simd-count) 计算单位数量(-cu-count) 固件和特性版本 (-firmware) GPU 系列,两个字母的首字母缩写(-family)SI - Southern Islands CI - Sea Islands KV - Kaveri VI - Volcanic Islands CZ - Carrizo AI - Arctic Islands RV - Raven 示例:
kubectl describe node cluster-node-23
Name: cluster-node-23
Roles: <none>
Labels: beta.amd.com/gpu.cu-count.64=1
beta.amd.com/gpu.device-id.6860=1
beta.amd.com/gpu.family.AI=1
beta.amd.com/gpu.simd-count.256=1
beta.amd.com/gpu.vram.16G=1
beta.kubernetes.io/arch=amd64
beta.kubernetes.io/os=linux
kubernetes.io/hostname=cluster-node-23
Annotations: kubeadm.alpha.kubernetes.io/cri-socket: /var/run/dockershim.sock
node.alpha.kubernetes.io/ttl: 0
......
使用了 Node Labeller 的时候,你可以在 Pod 的规约中指定 GPU 的类型:
apiVersion : v1
kind : Pod
metadata :
name : cuda-vector-add
spec :
restartPolicy : OnFailure
containers :
- name : cuda-vector-add
# https://github.com/kubernetes/kubernetes/blob/v1.7.11/test/images/nvidia-cuda/Dockerfile
image : "k8s.gcr.io/cuda-vector-add:v0.1"
resources :
limits :
nvidia.com/gpu : 1
nodeSelector :
accelerator : nvidia-tesla-p100 # or nvidia-tesla-k80 etc.
这能够保证 Pod 能够被调度到你所指定类型的 GPU 的节点上去。
5 - 教程 Kubernetes 文档的这一部分包含教程。每个教程展示了如何完成一个比单个
任务 更大的目标。
通常一个教程有几个部分,每个部分都有一系列步骤。在浏览每个教程之前,
您可能希望将标准化术语表 页面添加到书签,供以后参考。
基础知识 配置 无状态应用程序 有状态应用程序 集群 服务 接下来 如果您想编写教程,请参阅内容页面类型
以获取有关教程页面类型的信息。
5.1 - 你好,Minikube 本教程向你展示如何使用 Minikube 和 Katacoda
在 Kubernetes 上运行一个应用示例。Katacoda 提供免费的浏览器内 Kubernetes 环境。
教程目标 将一个示例应用部署到 Minikube。 运行应用程序。 查看应用日志 准备开始 本教程提供了容器镜像,使用 NGINX 来对所有请求做出回应:
创建 Minikube 集群 点击 启动终端
Launch Terminal 说明: 如果你在本地安装了 Minikube,运行 minikube start。
在运行 minikube dashboard 之前,你应该打开一个新终端,
在此启动 minikube dashboard ,然后切换回主终端。
在浏览器中打开 Kubernetes 仪表板(Dashboard):
仅限 Katacoda 环境:在终端窗口的顶部,单击加号,然后单击 选择要在主机 1 上查看的端口 。 仅限 Katacoda 环境:输入“30000”,然后单击 显示端口 。 说明: dashboard 命令启用仪表板插件,并在默认的 Web 浏览器中打开代理。你可以在仪表板上创建 Kubernetes 资源,例如 Deployment 和 Service。
如果你以 root 用户身份在环境中运行,
请参见使用 URL 打开仪表板 。
要停止代理,请运行 Ctrl+C 退出该进程。仪表板仍在运行中。
使用 URL 打开仪表板 如果你不想打开 Web 浏览器,请使用 url 标志运行显示板命令以得到 URL:
创建 Deployment Kubernetes Pod 是由一个或多个
为了管理和联网而绑定在一起的容器构成的组。 本教程中的 Pod 只有一个容器。
Kubernetes Deployment
检查 Pod 的健康状况,并在 Pod 中的容器终止的情况下重新启动新的容器。
Deployment 是管理 Pod 创建和扩展的推荐方法。
使用 kubectl create 命令创建管理 Pod 的 Deployment。该 Pod 根据提供的 Docker
镜像运行 Container。
kubectl create deployment hello-node --image= k8s.gcr.io/echoserver:1.4
查看 Deployment:
输出结果类似于这样:
NAME READY UP-TO-DATE AVAILABLE AGE
hello-node 1/1 1 1 1m
查看 Pod:
输出结果类似于这样:
NAME READY STATUS RESTARTS AGE
hello-node-5f76cf6ccf-br9b5 1/1 Running 0 1m
查看集群事件:
查看 kubectl 配置:
创建 Service 默认情况下,Pod 只能通过 Kubernetes 集群中的内部 IP 地址访问。
要使得 hello-node 容器可以从 Kubernetes 虚拟网络的外部访问,你必须将 Pod
暴露为 Kubernetes Service 。
使用 kubectl expose 命令将 Pod 暴露给公网:
kubectl expose deployment hello-node --type= LoadBalancer --port= 8080
这里的 --type=LoadBalancer 参数表明你希望将你的 Service 暴露到集群外部。
镜像 k8s.gcr.io/echoserver 中的应用程序代码仅监听 TCP 8080 端口。
如果你用 kubectl expose 暴露了其它的端口,客户端将不能访问其它端口。
查看你刚刚创建的 Service:
输出结果类似于这样:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
hello-node LoadBalancer 10.108.144.78 <pending> 8080:30369/TCP 21s
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 23m
对于支持负载均衡器的云服务平台而言,平台将提供一个外部 IP 来访问该服务。
在 Minikube 上,LoadBalancer 使得服务可以通过命令 minikube service 访问。
运行下面的命令:
minikube service hello-node
仅限 Katacoda 环境:单击加号,然后单击 选择要在主机 1 上查看的端口 。 仅限 Katacoda 环境:请注意在 service 输出中与 8080 对应的长度为 5 位的端口号。
此端口号是随机生成的,可能与你的不同。
在端口号文本框中输入你自己的端口号,然后单击显示端口。
对应于上面的例子,需要输入 30369。
这将打开一个浏览器窗口,为你的应用程序提供服务并显示应用的响应。
启用插件 Minikube 有一组内置的 插件 ,
可以在本地 Kubernetes 环境中启用、禁用和打开。
列出当前支持的插件:
输出结果类似于这样:
addon-manager: enabled
dashboard: enabled
default-storageclass: enabled
efk: disabled
freshpod: disabled
gvisor: disabled
helm-tiller: disabled
ingress: disabled
ingress-dns: disabled
logviewer: disabled
metrics-server: disabled
nvidia-driver-installer: disabled
nvidia-gpu-device-plugin: disabled
registry: disabled
registry-creds: disabled
storage-provisioner: enabled
storage-provisioner-gluster: disabled
启用插件,例如 metrics-server:
minikube addons enable metrics-server
输出结果类似于这样:
metrics-server was successfully enabled
查看刚才创建的 Pod 和 Service:
kubectl get pod,svc -n kube-system
输出结果类似于这样:
NAME READY STATUS RESTARTS AGE
pod/coredns-5644d7b6d9-mh9ll 1/1 Running 0 34m
pod/coredns-5644d7b6d9-pqd2t 1/1 Running 0 34m
pod/metrics-server-67fb648c5 1/1 Running 0 26s
pod/etcd-minikube 1/1 Running 0 34m
pod/influxdb-grafana-b29w8 2/2 Running 0 26s
pod/kube-addon-manager-minikube 1/1 Running 0 34m
pod/kube-apiserver-minikube 1/1 Running 0 34m
pod/kube-controller-manager-minikube 1/1 Running 0 34m
pod/kube-proxy-rnlps 1/1 Running 0 34m
pod/kube-scheduler-minikube 1/1 Running 0 34m
pod/storage-provisioner 1/1 Running 0 34m
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/metrics-server ClusterIP 10.96.241.45 <none> 80/TCP 26s
service/kube-dns ClusterIP 10.96.0.10 <none> 53/UDP,53/TCP 34m
service/monitoring-grafana NodePort 10.99.24.54 <none> 80:30002/TCP 26s
service/monitoring-influxdb ClusterIP 10.111.169.94 <none> 8083/TCP,8086/TCP 26s
禁用 metrics-server:
minikube addons disable metrics-server
输出结果类似于这样:
metrics-server was successfully disabled
清理 现在可以清理你在集群中创建的资源:
kubectl delete service hello-node
kubectl delete deployment hello-node
可选地,停止 Minikube 虚拟机(VM):
可选地,删除 Minikube 虚拟机(VM):
接下来 5.2 - 学习 Kubernetes 基础知识 Kubernetes 基础 本教程介绍了 Kubernetes 集群编排系统的基础知识。每个模块包含关于 Kubernetes 主要特性和概念的一些背景信息,并包括一个在线互动教程。这些互动教程让您可以自己管理一个简单的集群及其容器化应用程序。
使用互动教程,您可以学习:
在集群上部署容器化应用程序 弹性部署 使用新的软件版本,更新容器化应用程序 调试容器化应用程序 教程 Katacoda 在您的浏览器中运行一个虚拟终端,在浏览器中运行 Minikube,这是一个可在任何地方小规模本地部署的 Kubernetes 集群。不需要安装任何软件或进行任何配置;每个交互性教程都直接从您的网页浏览器上运行。
Kubernetes 可以为您做些什么? 通过现代的 Web 服务,用户希望应用程序能够 24/7 全天候使用,开发人员希望每天可以多次发布部署新版本的应用程序。 容器化可以帮助软件包达成这些目标,使应用程序能够以简单快速的方式发布和更新,而无需停机。Kubernetes 帮助您确保这些容器化的应用程序在您想要的时间和地点运行,并帮助应用程序找到它们需要的资源和工具。Kubernetes 是一个可用于生产的开源平台,根据 Google 容器集群方面积累的经验,以及来自社区的最佳实践而设计。
5.2.1 - 创建集群 5.2.1.1 - 使用 Minikube 创建集群 目标 了解 Kubernetes 集群。 了解 Minikube 。 使用在线终端开启一个 Kubernetes 集群。 Kubernetes 集群 Kubernetes 协调一个高可用计算机集群,每个计算机作为独立单元互相连接工作。 Kubernetes 中的抽象允许您将容器化的应用部署到集群,而无需将它们绑定到某个特定的独立计算机。为了使用这种新的部署模型,应用需要以将应用与单个主机分离的方式打包:它们需要被容器化。与过去的那种应用直接以包的方式深度与主机集成的部署模型相比,容器化应用更灵活、更可用。 Kubernetes 以更高效的方式跨集群自动分发和调度应用容器。 Kubernetes 是一个开源平台,并且可应用于生产环境。
一个 Kubernetes 集群包含两种类型的资源:
Master 调度整个集群Nodes 负责运行应用Kubernetes 是一个生产级别的开源平台,可协调在计算机集群内和跨计算机集群的应用容器的部署(调度)和执行.
Master 负责管理整个集群。 Master 协调集群中的所有活动,例如调度应用、维护应用的所需状态、应用扩容以及推出新的更新。
Node 是一个虚拟机或者物理机,它在 Kubernetes 集群中充当工作机器的角色 每个Node都有 Kubelet , 它管理 Node 而且是 Node 与 Master 通信的代理。 Node 还应该具有用于处理容器操作的工具,例如 Docker 或 rkt 。处理生产级流量的 Kubernetes 集群至少应具有三个 Node 。
Master 管理集群,Node 用于托管正在运行的应用。
在 Kubernetes 上部署应用时,您告诉 Master 启动应用容器。 Master 就编排容器在集群的 Node 上运行。 Node 使用 Master 暴露的 Kubernetes API 与 Master 通信。 终端用户也可以使用 Kubernetes API 与集群交互。
Kubernetes 既可以部署在物理机上也可以部署在虚拟机上。您可以使用 Minikube 开始部署 Kubernetes 集群。 Minikube 是一种轻量级的 Kubernetes 实现,可在本地计算机上创建 VM 并部署仅包含一个节点的简单集群。 Minikube 可用于 Linux , macOS 和 Windows 系统。Minikube CLI 提供了用于引导集群工作的多种操作,包括启动、停止、查看状态和删除。在本教程里,您可以使用预装有 Minikube 的在线终端进行体验。
既然您已经知道 Kubernetes 是什么,让我们转到在线教程并启动我们的第一个 Kubernetes 集群!
5.2.2 - 部署应用 5.2.2.1 - 使用 kubectl 创建 Deployment 目标 学习了解应用的部署 使用 kubectl 在 Kubernetes 上部署第一个应用 Kubernetes 部署 一旦运行了 Kubernetes 集群,就可以在其上部署容器化应用程序。
为此,您需要创建 Kubernetes Deployment 配置。Deployment 指挥 Kubernetes 如何创建和更新应用程序的实例。创建 Deployment 后,Kubernetes master 将应用程序实例调度到集群中的各个节点上。
创建应用程序实例后,Kubernetes Deployment 控制器会持续监视这些实例。 如果托管实例的节点关闭或被删除,则 Deployment 控制器会将该实例替换为群集中另一个节点上的实例。 这提供了一种自我修复机制来解决机器故障维护问题。
在没有 Kubernetes 这种编排系统之前,安装脚本通常用于启动应用程序,但它们不允许从机器故障中恢复。通过创建应用程序实例并使它们在节点之间运行, Kubernetes Deployments 提供了一种与众不同的应用程序管理方法。
Deployment 负责创建和更新应用程序的实例
部署你在 Kubernetes 上的第一个应用程序 您可以使用 Kubernetes 命令行界面 Kubectl 创建和管理 Deployment。Kubectl 使用 Kubernetes API 与集群进行交互。在本单元中,您将学习创建在 Kubernetes 集群上运行应用程序的 Deployment 所需的最常见的 Kubectl 命令。
创建 Deployment 时,您需要指定应用程序的容器映像以及要运行的副本数。您可以稍后通过更新 Deployment 来更改该信息; 模块 5 和 6 讨论了如何扩展和更新 Deployments。
应用程序需要打包成一种受支持的容器格式,以便部署在 Kubernetes 上
对于我们的第一次部署,我们将使用打包在 Docker 容器中的 Node.js 应用程序。
要创建 Node.js 应用程序并部署 Docker 容器,请按照
你好 Minikube 教程 .
现在您已经了解了 Deployment 的内容,让我们转到在线教程并部署我们的第一个应用程序!
5.2.3 - 了解你的应用 5.2.3.1 - 查看 pod 和工作节点 目标 了解 Kubernetes Pod。 了解 Kubernetes 工作节点。 对已部署的应用故障排除。 Kubernetes Pods 在模块 2 创建 Deployment 时, Kubernetes 添加了一个 Pod 来托管你的应用实例。Pod 是 Kubernetes 抽象出来的,表示一组一个或多个应用程序容器(如 Docker),以及这些容器的一些共享资源。这些资源包括:
共享存储,当作卷 网络,作为唯一的集群 IP 地址 有关每个容器如何运行的信息,例如容器映像版本或要使用的特定端口。 Pod 为特定于应用程序的“逻辑主机”建模,并且可以包含相对紧耦合的不同应用容器。例如,Pod 可能既包含带有 Node.js 应用的容器,也包含另一个不同的容器,用于提供 Node.js 网络服务器要发布的数据。Pod 中的容器共享 IP 地址和端口,始终位于同一位置并且共同调度,并在同一工作节点上的共享上下文中运行。
Pod是 Kubernetes 平台上的原子单元。 当我们在 Kubernetes 上创建 Deployment 时,该 Deployment 会在其中创建包含容器的 Pod (而不是直接创建容器)。每个 Pod 都与调度它的工作节点绑定,并保持在那里直到终止(根据重启策略)或删除。 如果工作节点发生故障,则会在群集中的其他可用工作节点上调度相同的 Pod。
Pod 是一组一个或多个应用程序容器(例如 Docker),包括共享存储(卷), IP 地址和有关如何运行它们的信息。
工作节点 一个 pod 总是运行在 工作节点 。工作节点是 Kubernetes 中的参与计算的机器,可以是虚拟机或物理计算机,具体取决于集群。每个工作节点由主节点管理。工作节点可以有多个 pod ,Kubernetes 主节点会自动处理在群集中的工作节点上调度 pod 。 主节点的自动调度考量了每个工作节点上的可用资源。
每个 Kubernetes 工作节点至少运行:
Kubelet,负责 Kubernetes 主节点和工作节点之间通信的过程; 它管理 Pod 和机器上运行的容器。 容器运行时(如 Docker)负责从仓库中提取容器镜像,解压缩容器以及运行应用程序。 如果它们紧耦合并且需要共享磁盘等资源,这些容器应在一个 Pod 中编排。
使用 kubectl 进行故障排除 在模块 2 ,您使用了 Kubectl 命令行界面。 您将继续在第3单元中使用它来获取有关已部署的应用程序及其环境的信息。 最常见的操作可以使用以下 kubectl 命令完成:
kubectl get - 列出资源kubectl describe - 显示有关资源的详细信息kubectl logs - 打印 pod 和其中容器的日志kubectl exec - 在 pod 中的容器上执行命令您可以使用这些命令查看应用程序的部署时间,当前状态,运行位置以及配置。
现在我们了解了有关集群组件和命令行的更多信息,让我们来探索一下我们的应用程序。
工作节点是 Kubernetes 中的负责计算的机器,可能是VM或物理计算机,具体取决于群集。多个 Pod 可以在一个工作节点上运行。
5.2.4 - 公开地暴露你的应用 5.2.4.1 - 使用 Service 暴露您的应用 目标 了解 Kubernetes 中的 Service 了解 标签(Label) 和 标签选择器(Label Selector) 对象如何与 Service 关联 在 Kubernetes 集群外用 Service 暴露应用 Kubernetes Service 总览 Kubernetes Pod 是转瞬即逝的。 Pod 实际上拥有 生命周期 。 当一个工作 Node 挂掉后, 在 Node 上运行的 Pod 也会消亡。 ReplicaSet 会自动地通过创建新的 Pod 驱动集群回到目标状态,以保证应用程序正常运行。 换一个例子,考虑一个具有3个副本数的用作图像处理的后端程序。这些副本是可替换的; 前端系统不应该关心后端副本,即使 Pod 丢失或重新创建。也就是说,Kubernetes 集群中的每个 Pod (即使是在同一个 Node 上的 Pod )都有一个惟一的 IP 地址,因此需要一种方法自动协调 Pod 之间的变更,以便应用程序保持运行。
Kubernetes 中的服务(Service)是一种抽象概念,它定义了 Pod 的逻辑集和访问 Pod 的协议。Service 使从属 Pod 之间的松耦合成为可能。 和其他 Kubernetes 对象一样, Service 用 YAML (更推荐) 或者 JSON 来定义. Service 下的一组 Pod 通常由 LabelSelector (请参阅下面的说明为什么您可能想要一个 spec 中不包含selector的服务)来标记。
尽管每个 Pod 都有一个唯一的 IP 地址,但是如果没有 Service ,这些 IP 不会暴露在群集外部。Service 允许您的应用程序接收流量。Service 也可以用在 ServiceSpec 标记type的方式暴露
ClusterIP (默认) - 在集群的内部 IP 上公开 Service 。这种类型使得 Service 只能从集群内访问。NodePort - 使用 NAT 在集群中每个选定 Node 的相同端口上公开 Service 。使用<NodeIP>:<NodePort> 从集群外部访问 Service。是 ClusterIP 的超集。LoadBalancer - 在当前云中创建一个外部负载均衡器(如果支持的话),并为 Service 分配一个固定的外部IP。是 NodePort 的超集。ExternalName - 通过返回带有该名称的 CNAME 记录,使用任意名称(由 spec 中的externalName指定)公开 Service。不使用代理。这种类型需要kube-dns的v1.7或更高版本。更多关于不同 Service 类型的信息可以在使用源 IP 教程。 也请参阅 连接应用程序和 Service 。
另外,需要注意的是有一些 Service 的用例没有在 spec 中定义selector。 一个没有selector创建的 Service 也不会创建相应的端点对象。这允许用户手动将服务映射到特定的端点。没有 selector 的另一种可能是您严格使用type: ExternalName来标记。
总结 将 Pod 暴露给外部通信 跨多个 Pod 的负载均衡 使用标签(Label) Kubernetes 的 Service 是一个抽象层,它定义了一组 Pod 的逻辑集,并为这些 Pod 支持外部流量暴露、负载平衡和服务发现。
Service 通过一组 Pod 路由通信。Service 是一种抽象,它允许 Pod 死亡并在 Kubernetes 中复制,而不会影响应用程序。在依赖的 Pod (如应用程序中的前端和后端组件)之间进行发现和路由是由Kubernetes Service 处理的。
Service 匹配一组 Pod 是使用 标签(Label)和选择器(Selector) , 它们是允许对 Kubernetes 中的对象进行逻辑操作的一种分组原语。标签(Label)是附加在对象上的键/值对,可以以多种方式使用:
指定用于开发,测试和生产的对象 嵌入版本标签 使用 Label 将对象进行分类 你也可以在创建 Deployment 的同时用 --expose创建一个 Service 。
标签(Label)可以在创建时或之后附加到对象上。他们可以随时被修改。现在使用 Service 发布我们的应用程序并添加一些 Label 。
5.2.5 - 缩放你的应用 5.2.5.1 - 运行应用程序的多个实例 扩缩应用程序 在之前的模块中,我们创建了一个 Deployment ,然后通过 Service 让其可以开放访问。Deployment 仅为跑这个应用程序创建了一个 Pod。 当流量增加时,我们需要扩容应用程序满足用户需求。
扩缩 是通过改变 Deployment 中的副本数量来实现的。
在运行 kubectl run 命令时,你可以通过设置 --replicas 参数来设置 Deployment 的副本数。
扩展 Deployment 将创建新的 Pods,并将资源调度请求分配到有可用资源的节点上,收缩 会将 Pods 数量减少至所需的状态。Kubernetes 还支持 Pods 的自动缩放 ,但这并不在本教程的讨论范围内。将 Pods 数量收缩到0也是可以的,但这会终止 Deployment 上所有已经部署的 Pods。
运行应用程序的多个实例需要在它们之间分配流量。服务 (Service)有一种负载均衡器类型,可以将网络流量均衡分配到外部可访问的 Pods 上。服务将会一直通过端点来监视 Pods 的运行,保证流量只分配到可用的 Pods 上。
扩缩是通过改变 Deployment 中的副本数量来实现的。
一旦有了多个应用实例,就可以没有宕机地滚动更新。我们将会在下面的模块中介绍这些。现在让我们使用在线终端来体验一下应用程序的扩缩过程。
5.2.6 - 更新你的应用 5.2.6.1 - 执行滚动更新 更新应用程序 用户希望应用程序始终可用,而开发人员则需要每天多次部署它们的新版本。在 Kubernetes 中,这些是通过滚动更新(Rolling Updates)完成的。 滚动更新 允许通过使用新的实例逐步更新 Pod 实例,零停机进行 Deployment 更新。新的 Pod 将在具有可用资源的节点上进行调度。
在前面的模块中,我们将应用程序扩展为运行多个实例。这是在不影响应用程序可用性的情况下执行更新的要求。默认情况下,更新期间不可用的 pod 的最大值和可以创建的新 pod 数都是 1。这两个选项都可以配置为(pod)数字或百分比。
在 Kubernetes 中,更新是经过版本控制的,任何 Deployment 更新都可以恢复到以前的(稳定)版本。
滚动更新允许通过使用新的实例逐步更新 Pod 实例从而实现 Deployments 更新,停机时间为零。
与应用程序扩展类似,如果公开了 Deployment,服务将在更新期间仅对可用的 pod 进行负载均衡。可用 Pod 是应用程序用户可用的实例。
滚动更新允许以下操作:
将应用程序从一个环境提升到另一个环境(通过容器镜像更新) 回滚到以前的版本 持续集成和持续交付应用程序,无需停机 如果 Deployment 是公开的,则服务将仅在更新期间对可用的 pod 进行负载均衡。
在下面的交互式教程中,我们将应用程序更新为新版本,并执行回滚。
5.3 - 配置 5.3.1.1 - 使用 MicroProfile、ConfigMaps、Secrets 实现外部化应用配置 在本教程中,你会学到如何以及为什么要实现外部化微服务应用配置。
具体来说,你将学习如何使用 Kubernetes ConfigMaps 和 Secrets 设置环境变量,
然后在 MicroProfile config 中使用它们。
准备开始 创建 Kubernetes ConfigMaps 和 Secrets 在 Kubernetes 中,为 docker 容器设置环境变量有几种不同的方式,比如:
Dockerfile、kubernetes.yml、Kubernetes ConfigMaps、和 Kubernetes Secrets。
在本教程中,你将学到怎么用后两个方式去设置你的环境变量,而环境变量的值将注入到你的微服务里。
使用 ConfigMaps 和 Secrets 的一个好处是他们能在多个容器间复用,
比如赋值给不同的容器中的不同环境变量。
ConfigMaps 是存储非机密键值对的 API 对象。
在互动教程中,你会学到如何用 ConfigMap 来保存应用名字。
ConfigMap 的更多信息,你可以在这里 找到文档。
Secrets 尽管也用来存储键值对,但区别于 ConfigMaps 的是:它针对机密/敏感数据,且存储格式为 Base64 编码。
secrets 的这种特性使得它适合于存储证书、密钥、令牌,上述内容你将在交互教程中实现。
Secrets 的更多信息,你可以在这里 找到文档。
从代码外部化配置 外部化应用配置之所以有用处,是因为配置常常根据环境的不同而变化。
为了实现此功能,我们用到了 Java 上下文和依赖注入(Contexts and Dependency Injection, CDI)、MicroProfile 配置。
MicroProfile config 是 MicroProfile 的功能特性,
是一组开放 Java 技术,用于开发、部署云原生微服务。
CDI 提供一套标准的依赖注入能力,使得应用程序可以由相互协作的、松耦合的 beans 组装而成。
MicroProfile Config 为 app 和微服务提供从各种来源,比如应用、运行时、环境,获取配置参数的标准方法。
基于来源定义的优先级,属性可以自动的合并到单独一组应用可以通过 API 访问到的属性。
CDI & MicroProfile 都会被用在互动教程中,
用来从 Kubernetes ConfigMaps 和 Secrets 获得外部提供的属性,并注入应用程序代码中。
很多开源框架、运行时支持 MicroProfile Config。
对于整个互动教程,你都可以使用开放的库、灵活的开源 Java 运行时,去构建并运行云原生的 apps 和微服务。
然而,任何 MicroProfile 兼容的运行时都可以用来做替代品。
教程目标 创建 Kubernetes ConfigMap 和 Secret 使用 MicroProfile Config 注入微服务配置 示例:使用 MicroProfile、ConfigMaps、Secrets 实现外部化应用配置 5.3.1.2 - 互动教程 - 配置 java 微服务 5.3.2 - 使用 ConfigMap 来配置 Redis 这篇文档基于使用 ConfigMap 来配置 Containers 这个任务,提供了一个使用 ConfigMap 来配置 Redis 的真实案例。
教程目标 创建一个包含以下内容的 kustomization.yaml 文件: 一个 ConfigMap 生成器 一个使用 ConfigMap 的 Pod 资源配置 使用 kubectl apply -k ./ 应用整个路径的配置 验证配置已经被正确应用。 准备开始 真实世界的案例:使用 ConfigMap 来配置 Redis 按照下面的步骤,您可以使用ConfigMap中的数据来配置Redis缓存。
根据docs/user-guide/configmap/redis/redis-config来创建一个ConfigMap: maxmemory 2mb
maxmemory-policy allkeys-lru
curl -OL https://k8s.io/examples/pods/config/redis-config
cat <<EOF >./kustomization.yaml
configMapGenerator:
- name: example-redis-config
files:
- redis-config
EOF
将 pod 的资源配置添加到 kustomization.yaml 文件中:
apiVersion : v1
kind : Pod
metadata :
name : redis
spec :
containers :
- name : redis
image : redis:5.0.4
command :
- redis-server
- "/redis-master/redis.conf"
env :
- name : MASTER
value : "true"
ports :
- containerPort : 6379
resources :
limits :
cpu : "0.1"
volumeMounts :
- mountPath : /redis-master-data
name : data
- mountPath : /redis-master
name : config
volumes :
- name : data
emptyDir : {}
- name : config
configMap :
name : example-redis-config
items :
- key : redis-config
path : redis.conf
curl -OL https://raw.githubusercontent.com/kubernetes/website/master/content/en/examples/pods/config/redis-pod.yaml
cat <<EOF >>./kustomization.yaml
resources:
- redis-pod.yaml
EOF
应用整个 kustomization 文件夹以创建 ConfigMap 和 Pod 对象:
使用以下命令检查创建的对象
> kubectl get -k .
NAME DATA AGE
configmap/example-redis-config-dgh9dg555m 1 52s
NAME READY STATUS RESTARTS AGE
pod/redis 1/1 Running 0 52s
在示例中,配置卷挂载在 /redis-master 下。
它使用 path 将 redis-config 密钥添加到名为 redis.conf 的文件中。
因此,redis配置的文件路径为 /redis-master/redis.conf。
这是镜像将在其中查找 redis master 的配置文件的位置。
使用 kubectl exec 进入 pod 并运行 redis-cli 工具来验证配置已正确应用:
kubectl exec -it redis -- redis-cli
127.0.0.1:6379> CONFIG GET maxmemory
1) "maxmemory"
2) "2097152"
127.0.0.1:6379> CONFIG GET maxmemory-policy
1) "maxmemory-policy"
2) "allkeys-lru"
删除创建的 pod:
接下来
5.4 - 无状态应用程序 5.4.1 - 公开外部 IP 地址以访问集群中应用程序 此页面显示如何创建公开外部 IP 地址的 Kubernetes 服务对象。
准备开始 安装 kubectl . 使用 Google Kubernetes Engine 或 Amazon Web Services 等云供应商创建 Kubernetes 集群。
本教程创建了一个外部负载均衡器 ,
需要云供应商。 配置 kubectl 与 Kubernetes API 服务器通信。有关说明,请参阅云供应商文档。 教程目标 运行 Hello World 应用程序的五个实例。 创建一个公开外部 IP 地址的 Service 对象。 使用 Service 对象访问正在运行的应用程序。 为一个在五个 pod 中运行的应用程序创建服务 在集群中运行 Hello World 应用程序:
apiVersion : apps/v1
kind : Deployment
metadata :
labels :
app.kubernetes.io/name : load-balancer-example
name : hello-world
spec :
replicas : 5
selector :
matchLabels :
app.kubernetes.io/name : load-balancer-example
template :
metadata :
labels :
app.kubernetes.io/name : load-balancer-example
spec :
containers :
- image : gcr.io/google-samples/node-hello:1.0
name : hello-world
ports :
- containerPort : 8080
kubectl apply -f https://k8s.io/examples/service/load-balancer-example.yaml
前面的命令创建一个
Deployment
对象和一个关联的
ReplicaSet 对象。
ReplicaSet 有五个 Pods ,
每个都运行 Hello World 应用程序。
显示有关 Deployment 的信息:
kubectl get deployments hello-world
kubectl describe deployments hello-world
显示有关 ReplicaSet 对象的信息:
kubectl get replicasets
kubectl describe replicasets
创建公开 Deployment 的 Service 对象:
kubectl expose deployment hello-world --type= LoadBalancer --name= my-service
显示有关 Service 的信息:
kubectl get services my-service
输出类似于:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
my-service LoadBalancer 10.3.245.137 104.198.205.71 8080/TCP 54s
提示:type=LoadBalancer 服务由外部云服务提供商提供支持,本例中不包含此部分,
详细信息请参考此页
提示:如果外部 IP 地址显示为 <pending>,请等待一分钟再次输入相同的命令。
显示有关 Service 的详细信息:
kubectl describe services my-service
输出类似于:
Name: my-service
Namespace: default
Labels: app.kubernetes.io/name=load-balancer-example
Annotations: <none>
Selector: app.kubernetes.io/name=load-balancer-example
Type: LoadBalancer
IP: 10.3.245.137
LoadBalancer Ingress: 104.198.205.71
Port: <unset> 8080/TCP
NodePort: <unset> 32377/TCP
Endpoints: 10.0.0.6:8080,10.0.1.6:8080,10.0.1.7:8080 + 2 more...
Session Affinity: None
Events: <none>
记下服务公开的外部 IP 地址(LoadBalancer Ingress)。
在本例中,外部 IP 地址是 104.198.205.71。还要注意 Port 和 NodePort 的值。
在本例中,Port 是 8080,NodePort 是32377。
在前面的输出中,您可以看到服务有几个端点:
10.0.0.6:8080、10.0.1.6:8080、10.0.1.7:8080 和另外两个,
这些都是正在运行 Hello World 应用程序的 pod 的内部地址。
要验证这些是 pod 地址,请输入以下命令:
kubectl get pods --output= wide
输出类似于:
NAME ... IP NODE
hello-world-2895499144-1jaz9 ... 10.0.1.6 gke-cluster-1-default-pool-e0b8d269-1afc
hello-world-2895499144-2e5uh ... 10.0.1.8 gke-cluster-1-default-pool-e0b8d269-1afc
hello-world-2895499144-9m4h1 ... 10.0.0.6 gke-cluster-1-default-pool-e0b8d269-5v7a
hello-world-2895499144-o4z13 ... 10.0.1.7 gke-cluster-1-default-pool-e0b8d269-1afc
hello-world-2895499144-segjf ... 10.0.2.5 gke-cluster-1-default-pool-e0b8d269-cpuc
使用外部 IP 地址(LoadBalancer Ingress)访问 Hello World 应用程序:
curl http://<external-ip>:<port>
其中 <external-ip> 是您的服务的外部 IP 地址(LoadBalancer Ingress),
<port> 是您的服务描述中的 port 的值。
如果您正在使用 minikube,输入 minikube service my-service 将在浏览器中自动打开 Hello World 应用程序。
成功请求的响应是一条问候消息:
清理现场 要删除服务,请输入以下命令:
kubectl delete services my-service
要删除正在运行 Hello World 应用程序的 Deployment,ReplicaSet 和 Pod,请输入以下命令:
kubectl delete deployment hello-world
接下来 进一步了解将应用程序与服务连接 。
5.4.2 - 示例:使用 MongoDB 部署 PHP 留言板应用程序 本教程向您展示如何使用 Kubernetes 和 Docker 构建和部署
一个简单的_(非面向生产)的_多层 web 应用程序。本例由以下组件组成:
教程目标 启动 Mongo 数据库。 启动留言板前端。 公开并查看前端服务。 清理。 准备开始 你必须拥有一个 Kubernetes 的集群,同时你的 Kubernetes 集群必须带有 kubectl 命令行工具。
如果你还没有集群,你可以通过 Minikube 构建一
个你自己的集群,或者你可以使用下面任意一个 Kubernetes 工具构建:
您的 Kubernetes 服务器版本必须不低于版本 v1.14.
要获知版本信息,请输入
kubectl version.
启动 Mongo 数据库 留言板应用程序使用 MongoDB 存储数据。
创建 Mongo 的 Deployment 下面包含的清单文件指定了一个 Deployment 控制器,该控制器运行一个 MongoDB Pod 副本。
apiVersion : apps/v1
kind : Deployment
metadata :
name : mongo
labels :
app.kubernetes.io/name : mongo
app.kubernetes.io/component : backend
spec :
selector :
matchLabels :
app.kubernetes.io/name : mongo
app.kubernetes.io/component : backend
replicas : 1
template :
metadata :
labels :
app.kubernetes.io/name : mongo
app.kubernetes.io/component : backend
spec :
containers :
- name : mongo
image : mongo:4.2
args :
- --bind_ip
- 0.0.0.0
resources :
requests :
cpu : 100m
memory : 100Mi
ports :
- containerPort : 27017
在下载清单文件的目录中启动终端窗口。
从 mongo-deployment.yaml 文件中应用 MongoDB Deployment:
kubectl apply -f https://k8s.io/examples/application/guestbook/mongo-deployment.yaml
查询 Pod 列表以验证 MongoDB Pod 是否正在运行:
响应应该与此类似:
```shell
NAME READY STATUS RESTARTS AGE
mongo-5cfd459dd4-lrcjb 1/1 Running 0 28s
```
运行以下命令查看 MongoDB Deployment 中的日志:
kubectl logs -f deployment/mongo
创建 MongoDB 服务 留言板应用程序需要往 MongoDB 中写数据。因此,需要创建 Service 来代理 MongoDB Pod 的流量。Service 定义了访问 Pod 的策略。
apiVersion : v1
kind : Service
metadata :
name : mongo
labels :
app.kubernetes.io/name : mongo
app.kubernetes.io/component : backend
spec :
ports :
- port : 27017
targetPort : 27017
selector :
app.kubernetes.io/name : mongo
app.kubernetes.io/component : backend
使用下面的 mongo-service.yaml 文件创建 MongoDB 的服务:
kubectl apply -f https://k8s.io/examples/application/guestbook/mongo-service.yaml
查询服务列表验证 MongoDB 服务是否正在运行:
响应应该与此类似:
```shell
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.0.0.1 <none> 443/TCP 1m
mongo ClusterIP 10.0.0.151 <none> 6379/TCP 8s
```
说明: 这个清单文件创建了一个名为 mongo 的 Service,其中包含一组与前面定义的标签匹配的标签,因此服务将网络流量路由到 MongoDB Pod 上。
设置并公开留言板前端 留言板应用程序有一个 web 前端,服务于用 PHP 编写的 HTTP 请求。
它被配置为连接到 mongo 服务以存储留言版条目。
创建留言板前端 Deployment apiVersion : apps/v1
kind : Deployment
metadata :
name : frontend
labels :
app.kubernetes.io/name : guestbook
app.kubernetes.io/component : frontend
spec :
selector :
matchLabels :
app.kubernetes.io/name : guestbook
app.kubernetes.io/component : frontend
replicas : 3
template :
metadata :
labels :
app.kubernetes.io/name : guestbook
app.kubernetes.io/component : frontend
spec :
containers :
- name : guestbook
image : paulczar/gb-frontend:v5
# image: gcr.io/google-samples/gb-frontend:v4
resources :
requests :
cpu : 100m
memory : 100Mi
env :
- name : GET_HOSTS_FROM
value : dns
ports :
- containerPort : 80
从 frontend-deployment.yaml 应用前端 Deployment 文件:
kubectl apply -f https://k8s.io/examples/application/guestbook/frontend-deployment.yaml
查询 Pod 列表,验证三个前端副本是否正在运行:
kubectl get pods -l app.kubernetes.io/name= guestbook -l app.kubernetes.io/component= frontend
响应应该与此类似:
```
NAME READY STATUS RESTARTS AGE
frontend-3823415956-dsvc5 1/1 Running 0 54s
frontend-3823415956-k22zn 1/1 Running 0 54s
frontend-3823415956-w9gbt 1/1 Running 0 54s
```
创建前端服务 应用的 mongo 服务只能在 Kubernetes 集群中访问,因为服务的默认类型是
ClusterIP 。ClusterIP 为服务指向的 Pod 集提供一个 IP 地址。这个 IP 地址只能在集群中访问。
如果您希望访客能够访问您的留言板,您必须将前端服务配置为外部可见的,以便客户端可以从 Kubernetes 集群之外请求服务。然而即便使用了 ClusterIP Kubernets 用户仍可以通过 kubectl port-forwart 访问服务。
说明: 一些云提供商,如 Google Compute Engine 或 Google Kubernetes Engine,支持外部负载均衡器。如果您的云提供商支持负载均衡器,并且您希望使用它,
只需取消注释 type: LoadBalancer 即可。
apiVersion : v1
kind : Service
metadata :
name : frontend
labels :
app.kubernetes.io/name : guestbook
app.kubernetes.io/component : frontend
spec :
# if your cluster supports it, uncomment the following to automatically create
# an external load-balanced IP for the frontend service.
# type: LoadBalancer
ports :
- port : 80
selector :
app.kubernetes.io/name : guestbook
app.kubernetes.io/component : frontend
从 frontend-service.yaml 文件中应用前端服务:
kubectl apply -f https://k8s.io/examples/application/guestbook/frontend-service.yaml
查询服务列表以验证前端服务正在运行:
响应应该与此类似:
```
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
frontend ClusterIP 10.0.0.112 <none> 80/TCP 6s
kubernetes ClusterIP 10.0.0.1 <none> 443/TCP 4m
mongo ClusterIP 10.0.0.151 <none> 6379/TCP 2m
```
通过 kubectl port-forward 查看前端服务 运行以下命令将本机的 8080 端口转发到服务的 80 端口。
kubectl port-forward svc/frontend 8080:80
响应应该与此类似:
```
Forwarding from 127.0.0.1:8080 -> 80
Forwarding from [::1]:8080 -> 80
```
在浏览器中加载 http://localhost:8080 页面以查看留言板。 通过 LoadBalancer 查看前端服务 如果您部署了 frontend-service.yaml。你需要找到 IP 地址来查看你的留言板。
运行以下命令以获取前端服务的 IP 地址。
kubectl get service frontend
响应应该与此类似:
```
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
frontend ClusterIP 10.51.242.136 109.197.92.229 80:32372/TCP 1m
```
复制外部 IP 地址,然后在浏览器中加载页面以查看留言板。 扩展 Web 前端 伸缩很容易是因为服务器本身被定义为使用一个 Deployment 控制器的 Service。
运行以下命令扩展前端 Pod 的数量:
kubectl scale deployment frontend --replicas= 5
查询 Pod 列表验证正在运行的前端 Pod 的数量:
响应应该类似于这样:
```
NAME READY STATUS RESTARTS AGE
frontend-3823415956-70qj5 1/1 Running 0 5s
frontend-3823415956-dsvc5 1/1 Running 0 54m
frontend-3823415956-k22zn 1/1 Running 0 54m
frontend-3823415956-w9gbt 1/1 Running 0 54m
frontend-3823415956-x2pld 1/1 Running 0 5s
mongo-1068406935-3lswp 1/1 Running 0 56m
```
运行以下命令缩小前端 Pod 的数量:
kubectl scale deployment frontend --replicas= 2
查询 Pod 列表验证正在运行的前端 Pod 的数量:
响应应该类似于这样:
```
NAME READY STATUS RESTARTS AGE
frontend-3823415956-k22zn 1/1 Running 0 1h
frontend-3823415956-w9gbt 1/1 Running 0 1h
mongo-1068406935-3lswp 1/1 Running 0 1h
```
清理现场 删除 Deployments 和服务还会删除正在运行的 Pod。使用标签用一个命令删除多个资源。
运行以下命令以删除所有 Pod,Deployments 和 Services。
kubectl delete deployment -l app.kubernetes.io/name= mongo
kubectl delete service -l app.kubernetes.io/name= mongo
kubectl delete deployment -l app.kubernetes.io/name= guestbook
kubectl delete service -l app.kubernetes.io/name= guestbook
响应应该是:
```
deployment.apps "mongo" deleted
service "mongo" deleted
deployment.apps "frontend" deleted
service "frontend" deleted
```
查询 Pod 列表,确认没有 Pod 在运行:
响应应该是:
```
No resources found.
```
接下来
5.5 - 有状态的应用 5.5.1 - 示例:使用 Persistent Volumes 部署 WordPress 和 MySQL 本示例描述了如何通过 Minikube 在 Kubernetes 上安装 WordPress 和 MySQL。这两个应用都使用 PersistentVolumes 和 PersistentVolumeClaims 保存数据。
PersistentVolume (PV)是一块集群里由管理员手动提供,或 kubernetes 通过 StorageClass 动态创建的存储。
PersistentVolumeClaim (PVC)是一个满足对 PV 存储需要的请求。PersistentVolumes 和 PersistentVolumeClaims 是独立于 Pod 生命周期而在 Pod 重启,重新调度甚至删除过程中保存数据。
警告: deployment 在生产场景中并不适合,它使用单实例 WordPress 和 MySQL Pods。考虑使用 WordPress Helm Chart 在生产场景中部署 WordPress。
说明: 本教程中提供的文件使用 GA Deployment API,并且特定于 kubernetes 1.9 或更高版本。如果您希望将本教程与 Kubernetes 的早期版本一起使用,请相应地更新 API 版本,或参考本教程的早期版本。
教程目标 创建 PersistentVolumeClaims 和 PersistentVolumes 创建 kustomization.yaml 使用Secret 生成器 MySQL 资源配置 WordPress 资源配置 应用整个 kustomization 目录 kubectl apply -k ./ 清理 准备开始
你必须拥有一个 Kubernetes 的集群,同时你的 Kubernetes 集群必须带有 kubectl 命令行工具。
如果你还没有集群,你可以通过 Minikube 构建一
个你自己的集群,或者你可以使用下面任意一个 Kubernetes 工具构建:
要获知版本信息,请输入
kubectl version.
此例在kubectl 1.14 或者更高版本有效。
下载下面的配置文件:
mysql-deployment.yaml
wordpress-deployment.yaml
创建 PersistentVolumeClaims 和 PersistentVolumes MySQL 和 Wordpress 都需要一个 PersistentVolume 来存储数据。他们的 PersistentVolumeClaims 将在部署步骤中创建。
许多群集环境都安装了默认的 StorageClass。如果在 PersistentVolumeClaim 中未指定 StorageClass,则使用群集的默认 StorageClass。
创建 PersistentVolumeClaim 时,将根据 StorageClass 配置动态设置 PersistentVolume。
警告: 在本地群集中,默认的 StorageClass 使用hostPath供应器。 hostPath卷仅适用于开发和测试。使用 hostPath 卷,您的数据位于 Pod 调度到的节点上的/tmp中,并且不会在节点之间移动。如果 Pod 死亡并被调度到群集中的另一个节点,或者该节点重新启动,则数据将丢失。
说明: 如果要建立需要使用hostPath设置程序的集群,则必须在 controller-manager 组件中设置--enable-hostpath-provisioner标志。
说明: 如果你已经有运行在 Google Kubernetes Engine 的集群,请参考 this guide 。
创建 kustomization.yaml 创建 Secret 生成器 A Secret 是存储诸如密码或密钥之类的敏感数据的对象。从 1.14 开始,kubectl支持使用 kustomization 文件管理 Kubernetes 对象。您可以通过kustomization.yaml中的生成器创建一个 Secret。
通过以下命令在kustomization.yaml中添加一个 Secret 生成器。您需要用您要使用的密码替换YOUR_PASSWORD。
cat <<EOF >./kustomization.yaml
secretGenerator:
- name: mysql-pass
literals:
- password=YOUR_PASSWORD
EOF
补充 MySQL 和 WordPress 的资源配置 以下 manifest 文件描述了单实例 MySQL 部署。MySQL 容器将 PersistentVolume 挂载在/var/lib/mysql。 MYSQL_ROOT_PASSWORD环境变量设置来自 Secret 的数据库密码。
apiVersion : v1
kind : Service
metadata :
name : wordpress-mysql
labels :
app : wordpress
spec :
ports :
- port : 3306
selector :
app : wordpress
tier : mysql
clusterIP : None
---
apiVersion : v1
kind : PersistentVolumeClaim
metadata :
name : mysql-pv-claim
labels :
app : wordpress
spec :
accessModes :
- ReadWriteOnce
resources :
requests :
storage : 20Gi
---
apiVersion : apps/v1
kind : Deployment
metadata :
name : wordpress-mysql
labels :
app : wordpress
spec :
selector :
matchLabels :
app : wordpress
tier : mysql
strategy :
type : Recreate
template :
metadata :
labels :
app : wordpress
tier : mysql
spec :
containers :
- image : mysql:5.6
name : mysql
env :
- name : MYSQL_ROOT_PASSWORD
valueFrom :
secretKeyRef :
name : mysql-pass
key : password
ports :
- containerPort : 3306
name : mysql
volumeMounts :
- name : mysql-persistent-storage
mountPath : /var/lib/mysql
volumes :
- name : mysql-persistent-storage
persistentVolumeClaim :
claimName : mysql-pv-claim
以下 manifest 文件描述了单实例 WordPress 部署。WordPress 容器将网站数据文件位于/var/www/html的 PersistentVolume。WORDPRESS_DB_HOST环境变量集上面定义的 MySQL Service 的名称,WordPress 将通过 Service 访问数据库。WORDPRESS_DB_PASSWORD环境变量设置从 Secret kustomize 生成的数据库密码。
apiVersion : v1
kind : Service
metadata :
name : wordpress
labels :
app : wordpress
spec :
ports :
- port : 80
selector :
app : wordpress
tier : frontend
type : LoadBalancer
---
apiVersion : v1
kind : PersistentVolumeClaim
metadata :
name : wp-pv-claim
labels :
app : wordpress
spec :
accessModes :
- ReadWriteOnce
resources :
requests :
storage : 20Gi
---
apiVersion : apps/v1
kind : Deployment
metadata :
name : wordpress
labels :
app : wordpress
spec :
selector :
matchLabels :
app : wordpress
tier : frontend
strategy :
type : Recreate
template :
metadata :
labels :
app : wordpress
tier : frontend
spec :
containers :
- image : wordpress:4.8-apache
name : wordpress
env :
- name : WORDPRESS_DB_HOST
value : wordpress-mysql
- name : WORDPRESS_DB_PASSWORD
valueFrom :
secretKeyRef :
name : mysql-pass
key : password
ports :
- containerPort : 80
name : wordpress
volumeMounts :
- name : wordpress-persistent-storage
mountPath : /var/www/html
volumes :
- name : wordpress-persistent-storage
persistentVolumeClaim :
claimName : wp-pv-claim
下载 MySQL deployment 配置文件。
curl -LO https://k8s.io/examples/application/wordpress/mysql-deployment.yaml
下载 WordPress 配置文件。
curl -LO https://k8s.io/examples/application/wordpress/wordpress-deployment.yaml
补充到 kustomization.yaml 文件。
cat <<EOF >>./kustomization.yaml
resources:
- mysql-deployment.yaml
- wordpress-deployment.yaml
EOF
应用和验证 kustomization.yaml包含用于部署 WordPress 网站的所有资源以及 MySQL 数据库。您可以通过以下方式应用目录
现在,您可以验证所有对象是否存在。
通过运行以下命令验证 Secret 是否存在:
响应应如下所示:
NAME TYPE DATA AGE
mysql-pass-c57bb4t7mf Opaque 1 9s
验证是否已动态配置 PersistentVolume:
说明: 设置和绑定 PV 可能要花费几分钟。
响应应如下所示:
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
mysql-pv-claim Bound pvc-8cbd7b2e-4044-11e9-b2bb-42010a800002 20Gi RWO standard 77s
wp-pv-claim Bound pvc-8cd0df54-4044-11e9-b2bb-42010a800002 20Gi RWO standard 77s
通过运行以下命令来验证 Pod 是否正在运行:
说明: 等待 Pod 状态变成RUNNING可能会花费几分钟。
响应应如下所示:
NAME READY STATUS RESTARTS AGE
wordpress-mysql-1894417608-x5dzt 1/1 Running 0 40s
通过运行以下命令来验证 Service 是否正在运行:
kubectl get services wordpress
响应应如下所示:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
wordpress ClusterIP 10.0.0.89 <pending> 80:32406/TCP 4m
说明: Minikube 只能通过 NodePort 公开服务。EXTERNAL-IP 始终处于挂起状态
运行以下命令以获取 WordPress 服务的 IP 地址:
minikube service wordpress --url
响应应如下所示:
http://1.2.3.4:32406
复制 IP 地址,然后将页面加载到浏览器中来查看您的站点。
您应该看到类似于以下屏幕截图的 WordPress 设置页面。
警告: 不要在此页面上保留 WordPress 安装。如果其他用户找到了它,他们可以在您的实例上建立一个网站并使用它来提供恶意内容。 通过创建用户名和密码来安装 WordPress 或删除您的实例。
清理现场 运行一下命令删除您的 Secret,Deployments,Services and PersistentVolumeClaims:
接下来 5.5.2 - 运行 ZooKeeper,一个分布式协调系统 本教程展示了在 Kubernetes 上使用
StatefulSet ,
PodDisruptionBudget 和
PodAntiAffinity
特性运行 Apache Zookeeper 。
准备开始 在开始本教程前,你应该熟悉以下 Kubernetes 概念。
你需要一个至少包含四个节点的集群,每个节点至少 2 CPUs 和 4 GiB 内存。
在本教程中你将会隔离(Cordon)和腾空(Drain )集群的节点。
这意味着集群节点上所有的 Pods 将会被终止并移除。这些节点也会暂时变为不可调度 。
在本教程中你应该使用一个独占的集群,或者保证你造成的干扰不会影响其它租户。
本教程假设你的集群配置为动态的提供 PersistentVolumes。
如果你的集群没有配置成这样,在开始本教程前,你需要手动准备三个 20 GiB 的卷。
教程目标 在学习本教程后,你将熟悉下列内容。
如何使用 StatefulSet 部署一个 ZooKeeper ensemble。 如何一致性配置 ensemble。 如何在 ensemble 中 分布 ZooKeeper 服务器的部署。 如何在计划维护中使用 PodDisruptionBudgets 确保服务可用性。 ZooKeeper Apache ZooKeeper
是一个分布式的开源协调服务,用于分布式系统。
ZooKeeper 允许你读取、写入数据和发现数据更新。
数据按层次结构组织在文件系统中,并复制到 ensemble(一个 ZooKeeper 服务器的集合)
中所有的 ZooKeeper 服务器。对数据的所有操作都是原子的和顺序一致的。
ZooKeeper 通过
Zab
一致性协议在 ensemble 的所有服务器之间复制一个状态机来确保这个特性。
Ensemble 使用 Zab 协议选举一个领导者,在选举出领导者前不能写入数据。
一旦选举出了领导者,ensemble 使用 Zab 保证所有写入被复制到一个 quorum,
然后这些写入操作才会被确认并对客户端可用。
如果没有遵照加权 quorums,一个 quorum 表示包含当前领导者的 ensemble 的多数成员。
例如,如果 ensemble 有 3 个服务器,一个包含领导者的成员和另一个服务器就组成了一个
quorum。
如果 ensemble 不能达成一个 quorum,数据将不能被写入。
ZooKeeper 在内存中保存它们的整个状态机,但是每个改变都被写入一个在存储介质上的
持久 WAL(Write Ahead Log)。
当一个服务器出现故障时,它能够通过回放 WAL 恢复之前的状态。
为了防止 WAL 无限制的增长,ZooKeeper 服务器会定期的将内存状态快照保存到存储介质。
这些快照能够直接加载到内存中,所有在这个快照之前的 WAL 条目都可以被安全的丢弃。
创建一个 ZooKeeper Ensemble 下面的清单包含一个
无头服务 ,
一个 Service ,
一个 PodDisruptionBudget ,
和一个 StatefulSet 。
apiVersion : v1
kind : Service
metadata :
name : zk-hs
labels :
app : zk
spec :
ports :
- port : 2888
name : server
- port : 3888
name : leader-election
clusterIP : None
selector :
app : zk
---
apiVersion : v1
kind : Service
metadata :
name : zk-cs
labels :
app : zk
spec :
ports :
- port : 2181
name : client
selector :
app : zk
---
apiVersion : policy/v1beta1
kind : PodDisruptionBudget
metadata :
name : zk-pdb
spec :
selector :
matchLabels :
app : zk
maxUnavailable : 1
---
apiVersion : apps/v1
kind : StatefulSet
metadata :
name : zk
spec :
selector :
matchLabels :
app : zk
serviceName : zk-hs
replicas : 3
updateStrategy :
type : RollingUpdate
podManagementPolicy : OrderedReady
template :
metadata :
labels :
app : zk
spec :
affinity :
podAntiAffinity :
requiredDuringSchedulingIgnoredDuringExecution :
- labelSelector :
matchExpressions :
- key : "app"
operator : In
values :
- zk
topologyKey : "kubernetes.io/hostname"
containers :
- name : kubernetes-zookeeper
imagePullPolicy : Always
image : "k8s.gcr.io/kubernetes-zookeeper:1.0-3.4.10"
resources :
requests :
memory : "1Gi"
cpu : "0.5"
ports :
- containerPort : 2181
name : client
- containerPort : 2888
name : server
- containerPort : 3888
name : leader-election
command :
- sh
- -c
- "start-zookeeper \
--servers=3 \
--data_dir=/var/lib/zookeeper/data \
--data_log_dir=/var/lib/zookeeper/data/log \
--conf_dir=/opt/zookeeper/conf \
--client_port=2181 \
--election_port=3888 \
--server_port=2888 \
--tick_time=2000 \
--init_limit=10 \
--sync_limit=5 \
--heap=512M \
--max_client_cnxns=60 \
--snap_retain_count=3 \
--purge_interval=12 \
--max_session_timeout=40000 \
--min_session_timeout=4000 \
--log_level=INFO"
readinessProbe :
exec :
command :
- sh
- -c
- "zookeeper-ready 2181"
initialDelaySeconds : 10
timeoutSeconds : 5
livenessProbe :
exec :
command :
- sh
- -c
- "zookeeper-ready 2181"
initialDelaySeconds : 10
timeoutSeconds : 5
volumeMounts :
- name : datadir
mountPath : /var/lib/zookeeper
securityContext :
runAsUser : 1000
fsGroup : 1000
volumeClaimTemplates :
- metadata :
name : datadir
spec :
accessModes : [ "ReadWriteOnce" ]
resources :
requests :
storage : 10Gi
打开一个命令行终端,使用命令
kubectl apply
创建这个清单。
kubectl apply -f https://k8s.io/examples/application/zookeeper/zookeeper.yaml
这个操作创建了 zk-hs 无头服务、zk-cs 服务、zk-pdb PodDisruptionBudget
和 zk StatefulSet。
service/zk-hs created
service/zk-cs created
poddisruptionbudget.policy/zk-pdb created
statefulset.apps/zk created
使用命令
kubectl get
查看 StatefulSet 控制器创建的 Pods。
kubectl get pods -w -l app = zk
一旦 zk-2 Pod 变成 Running 和 Ready 状态,使用 CRTL-C 结束 kubectl。
NAME READY STATUS RESTARTS AGE
zk-0 0/1 Pending 0 0s
zk-0 0/1 Pending 0 0s
zk-0 0/1 ContainerCreating 0 0s
zk-0 0/1 Running 0 19s
zk-0 1/1 Running 0 40s
zk-1 0/1 Pending 0 0s
zk-1 0/1 Pending 0 0s
zk-1 0/1 ContainerCreating 0 0s
zk-1 0/1 Running 0 18s
zk-1 1/1 Running 0 40s
zk-2 0/1 Pending 0 0s
zk-2 0/1 Pending 0 0s
zk-2 0/1 ContainerCreating 0 0s
zk-2 0/1 Running 0 19s
zk-2 1/1 Running 0 40s
StatefulSet 控制器创建 3 个 Pods,每个 Pod 包含一个
ZooKeeper 服务器。
促成 Leader 选举 由于在匿名网络中没有用于选举 leader 的终止算法,Zab 要求显式的进行成员关系配置,
以执行 leader 选举。Ensemble 中的每个服务器都需要具有一个独一无二的标识符,
所有的服务器均需要知道标识符的全集,并且每个标识符都需要和一个网络地址相关联。
使用命令
kubectl exec
获取 zk StatefulSet 中 Pods 的主机名。
for i in 0 1 2; do kubectl exec zk-$i -- hostname; done
StatefulSet 控制器基于每个 Pod 的序号索引为它们各自提供一个唯一的主机名。
主机名采用 <statefulset 名称>-<序数索引> 的形式。
由于 zk StatefulSet 的 replicas 字段设置为 3,这个集合的控制器将创建
3 个 Pods,主机名为:zk-0、zk-1 和 zk-2。
zk-0
zk-1
zk-2
ZooKeeper ensemble 中的服务器使用自然数作为唯一标识符,
每个服务器的标识符都保存在服务器的数据目录中一个名为 myid 的文件里。
检查每个服务器的 myid 文件的内容。
for i in 0 1 2; do echo "myid zk- $i " ;kubectl exec zk-$i -- cat /var/lib/zookeeper/data/myid; done
由于标识符为自然数并且序号索引是非负整数,你可以在序号上加 1 来生成一个标识符。
myid zk-0
1
myid zk-1
2
myid zk-2
3
获取 zk StatefulSet 中每个 Pod 的全限定域名(Fully Qualified Domain Name,FQDN)。
for i in 0 1 2; do kubectl exec zk-$i -- hostname -f; done
zk-hs Service 为所有 Pods 创建了一个域:zk-hs.default.svc.cluster.local。
zk-0.zk-hs.default.svc.cluster.local
zk-1.zk-hs.default.svc.cluster.local
zk-2.zk-hs.default.svc.cluster.local
Kubernetes DNS
中的 A 记录将 FQDNs 解析成为 Pods 的 IP 地址。
如果 Pods 被调度,这个 A 记录将会使用 Pods 的新 IP 地址完成更新,
但 A 记录的名称不会改变。
ZooKeeper 在一个名为 zoo.cfg 的文件中保存它的应用配置。
使用 kubectl exec 在 zk-0 Pod 中查看 zoo.cfg 文件的内容。
kubectl exec zk-0 -- cat /opt/zookeeper/conf/zoo.cfg
文件底部为 server.1、server.2 和 server.3,其中的 1、2 和 3
分别对应 ZooKeeper 服务器的 myid 文件中的标识符。
它们被设置为 zk StatefulSet 中的 Pods 的 FQDNs。
clientPort=2181
dataDir=/var/lib/zookeeper/data
dataLogDir=/var/lib/zookeeper/log
tickTime=2000
initLimit=10
syncLimit=2000
maxClientCnxns=60
minSessionTimeout= 4000
maxSessionTimeout= 40000
autopurge.snapRetainCount=3
autopurge.purgeInterval=0
server.1=zk-0.zk-hs.default.svc.cluster.local:2888:3888
server.2=zk-1.zk-hs.default.svc.cluster.local:2888:3888
server.3=zk-2.zk-hs.default.svc.cluster.local:2888:3888
达成共识 一致性协议要求每个参与者的标识符唯一。
在 Zab 协议里任何两个参与者都不应该声明相同的唯一标识符。
对于让系统中的进程协商哪些进程已经提交了哪些数据而言,这是必须的。
如果有两个 Pods 使用相同的序号启动,这两个 ZooKeeper 服务器
会将自己识别为相同的服务器。
kubectl get pods -w -l app = zk
NAME READY STATUS RESTARTS AGE
zk-0 0/1 Pending 0 0s
zk-0 0/1 Pending 0 0s
zk-0 0/1 ContainerCreating 0 0s
zk-0 0/1 Running 0 19s
zk-0 1/1 Running 0 40s
zk-1 0/1 Pending 0 0s
zk-1 0/1 Pending 0 0s
zk-1 0/1 ContainerCreating 0 0s
zk-1 0/1 Running 0 18s
zk-1 1/1 Running 0 40s
zk-2 0/1 Pending 0 0s
zk-2 0/1 Pending 0 0s
zk-2 0/1 ContainerCreating 0 0s
zk-2 0/1 Running 0 19s
zk-2 1/1 Running 0 40s
每个 Pod 的 A 记录仅在 Pod 变成 Ready状态时被录入。
因此,ZooKeeper 服务器的 FQDNs 只会解析到一个端点,而那个端点将会是
一个唯一的 ZooKeeper 服务器,这个服务器声明了配置在它的 myid
文件中的标识符。
zk-0.zk-hs.default.svc.cluster.local
zk-1.zk-hs.default.svc.cluster.local
zk-2.zk-hs.default.svc.cluster.local
这保证了 ZooKeepers 的 zoo.cfg 文件中的 servers 属性代表了
一个正确配置的 ensemble。
server.1=zk-0.zk-hs.default.svc.cluster.local:2888:3888
server.2=zk-1.zk-hs.default.svc.cluster.local:2888:3888
server.3=zk-2.zk-hs.default.svc.cluster.local:2888:3888
当服务器使用 Zab 协议尝试提交一个值的时候,它们会达成一致并成功提交这个值
(如果领导者选举成功并且至少有两个 Pods 处于 Running 和 Ready状态),
或者将会失败(如果没有满足上述条件中的任意一条)。
当一个服务器承认另一个服务器的代写时不会有状态产生。
Ensemble 健康检查 最基本的健康检查是向一个 ZooKeeper 服务器写入一些数据,然后从
另一个服务器读取这些数据。
使用 zkCli.sh 脚本在 zk-0 Pod 上写入 world 到路径 /hello。
kubectl exec zk-0 zkCli.sh create /hello world
WATCHER::
WatchedEvent state:SyncConnected type:None path:null
Created /hello
使用下面的命令从 zk-1 Pod 获取数据。
kubectl exec zk-1 zkCli.sh get /hello
你在 zk-0 上创建的数据在 ensemble 中所有的服务器上都是可用的。
WATCHER::
WatchedEvent state:SyncConnected type:None path:null
world
cZxid = 0x100000002
ctime = Thu Dec 08 15:13:30 UTC 2016
mZxid = 0x100000002
mtime = Thu Dec 08 15:13:30 UTC 2016
pZxid = 0x100000002
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 5
numChildren = 0
提供持久存储 如同在 ZooKeeper 一节所提到的,ZooKeeper 提交
所有的条目到一个持久 WAL,并周期性的将内存快照写入存储介质。
对于使用一致性协议实现一个复制状态机的应用来说,使用 WALs 提供持久化
是一种常用的技术,对于普通的存储应用也是如此。
使用 kubectl delete
删除 zk StatefulSet。
kubectl delete statefulset zk
statefulset.apps "zk" deleted
观察 StatefulSet 中的 Pods 变为终止状态。
kubectl get pods -w -l app = zk
当 zk-0 完全终止时,使用 CRTL-C 结束 kubectl。
zk-2 1/1 Terminating 0 9m
zk-0 1/1 Terminating 0 11m
zk-1 1/1 Terminating 0 10m
zk-2 0/1 Terminating 0 9m
zk-2 0/1 Terminating 0 9m
zk-2 0/1 Terminating 0 9m
zk-1 0/1 Terminating 0 10m
zk-1 0/1 Terminating 0 10m
zk-1 0/1 Terminating 0 10m
zk-0 0/1 Terminating 0 11m
zk-0 0/1 Terminating 0 11m
zk-0 0/1 Terminating 0 11m
重新应用 zookeeper.yaml 中的清单。
kubectl apply -f https://k8s.io/examples/application/zookeeper/zookeeper.yaml
zk StatefulSet 将会被创建。由于清单中的其他 API 对象已经存在,所以它们不会被修改。
观察 StatefulSet 控制器重建 StatefulSet 的 Pods。
kubectl get pods -w -l app = zk
一旦 zk-2 Pod 处于 Running 和 Ready 状态,使用 CRTL-C 停止 kubectl命令。
NAME READY STATUS RESTARTS AGE
zk-0 0/1 Pending 0 0s
zk-0 0/1 Pending 0 0s
zk-0 0/1 ContainerCreating 0 0s
zk-0 0/1 Running 0 19s
zk-0 1/1 Running 0 40s
zk-1 0/1 Pending 0 0s
zk-1 0/1 Pending 0 0s
zk-1 0/1 ContainerCreating 0 0s
zk-1 0/1 Running 0 18s
zk-1 1/1 Running 0 40s
zk-2 0/1 Pending 0 0s
zk-2 0/1 Pending 0 0s
zk-2 0/1 ContainerCreating 0 0s
zk-2 0/1 Running 0 19s
zk-2 1/1 Running 0 40s
从 zk-2 Pod 中获取你在健康检查 中输入的值。
kubectl exec zk-2 zkCli.sh get /hello
尽管 zk StatefulSet 中所有的 Pods 都已经被终止并重建过,ensemble
仍然使用原来的数值提供服务。
WATCHER::
WatchedEvent state:SyncConnected type:None path:null
world
cZxid = 0x100000002
ctime = Thu Dec 08 15:13:30 UTC 2016
mZxid = 0x100000002
mtime = Thu Dec 08 15:13:30 UTC 2016
pZxid = 0x100000002
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 5
numChildren = 0
zk StatefulSet 的 spec 中的 volumeClaimTemplates 字段标识了
将要为每个 Pod 准备的 PersistentVolume。
volumeClaimTemplates :
- metadata :
name : datadir
annotations :
volume.alpha.kubernetes.io/storage-class : anything
spec :
accessModes : [ "ReadWriteOnce" ]
resources :
requests :
storage : 20Gi
StatefulSet 控制器为 StatefulSet 中的每个 Pod 生成一个 PersistentVolumeClaim。
获取 StatefulSet 的 PersistentVolumeClaim。
kubectl get pvc -l app = zk
当 StatefulSet 重新创建它的 Pods 时,Pods 的 PersistentVolumes 会被重新挂载。
NAME STATUS VOLUME CAPACITY ACCESSMODES AGE
datadir-zk-0 Bound pvc-bed742cd-bcb1-11e6-994f-42010a800002 20Gi RWO 1h
datadir-zk-1 Bound pvc-bedd27d2-bcb1-11e6-994f-42010a800002 20Gi RWO 1h
datadir-zk-2 Bound pvc-bee0817e-bcb1-11e6-994f-42010a800002 20Gi RWO 1h
StatefulSet 的容器 template 中的 volumeMounts 一节使得
PersistentVolumes 被挂载到 ZooKeeper 服务器的数据目录。
volumeMounts:
- name: datadir
mountPath: /var/lib/zookeeper
当 zk StatefulSet 中的一个 Pod 被(重新)调度时,它总是拥有相同的 PersistentVolume,
挂载到 ZooKeeper 服务器的数据目录。
即使在 Pods 被重新调度时,所有对 ZooKeeper 服务器的 WALs 的写入和它们的
全部快照都仍然是持久的。
确保一致性配置 如同在促成领导者选举 和达成一致
小节中提到的,ZooKeeper ensemble 中的服务器需要一致性的配置来选举一个领导者并形成一个
quorum。它们还需要 Zab 协议的一致性配置来保证这个协议在网络中正确的工作。
在这次的示例中,我们通过直接将配置写入代码清单中来达到该目的。
获取 zk StatefulSet。
kubectl get sts zk -o yaml
...
command:
- sh
- -c
- "start-zookeeper \
--servers=3 \
--data_dir=/var/lib/zookeeper/data \
--data_log_dir=/var/lib/zookeeper/data/log \
--conf_dir=/opt/zookeeper/conf \
--client_port=2181 \
--election_port=3888 \
--server_port=2888 \
--tick_time=2000 \
--init_limit=10 \
--sync_limit=5 \
--heap=512M \
--max_client_cnxns=60 \
--snap_retain_count=3 \
--purge_interval=12 \
--max_session_timeout=40000 \
--min_session_timeout=4000 \
--log_level=INFO"
...
用于启动 ZooKeeper 服务器的命令将这些配置作为命令行参数传给了 ensemble。
你也可以通过环境变量来传入这些配置。
配置日志 zkGenConfig.sh 脚本产生的一个文件控制了 ZooKeeper 的日志行为。
ZooKeeper 使用了 Log4j 并默认使用
基于文件大小和时间的滚动文件追加器作为日志配置。
从 zk StatefulSet 的一个 Pod 中获取日志配置。
kubectl exec zk-0 cat /usr/etc/zookeeper/log4j.properties
下面的日志配置会使 ZooKeeper 进程将其所有的日志写入标志输出文件流中。
zookeeper.root.logger=CONSOLE
zookeeper.console.threshold=INFO
log4j.rootLogger=${zookeeper.root.logger}
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.Threshold=${zookeeper.console.threshold}
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=%d{ISO8601} [myid:%X{myid}] - %-5p [%t:%C{1}@%L] - %m%n
这是在容器里安全记录日志的最简单的方法。
由于应用的日志被写入标准输出,Kubernetes 将会为你处理日志轮转。
Kubernetes 还实现了一个智能保存策略,保证写入标准输出和标准错误流
的应用日志不会耗尽本地存储媒介。
使用命令 kubectl logs
从一个 Pod 中取回最后 20 行日志。
kubectl logs zk-0 --tail 20
使用 kubectl logs 或者从 Kubernetes Dashboard 可以查看写入到标准输出和标准错误流中的应用日志。
2016-12-06 19:34:16,236 [myid:1] - INFO [NIOServerCxn.Factory:0.0.0.0/0.0.0.0:2181:NIOServerCnxn@827] - Processing ruok command from /127.0.0.1:52740
2016-12-06 19:34:16,237 [myid:1] - INFO [Thread-1136:NIOServerCnxn@1008] - Closed socket connection for client /127.0.0.1:52740 (no session established for client)
2016-12-06 19:34:26,155 [myid:1] - INFO [NIOServerCxn.Factory:0.0.0.0/0.0.0.0:2181:NIOServerCnxnFactory@192] - Accepted socket connection from /127.0.0.1:52749
2016-12-06 19:34:26,155 [myid:1] - INFO [NIOServerCxn.Factory:0.0.0.0/0.0.0.0:2181:NIOServerCnxn@827] - Processing ruok command from /127.0.0.1:52749
2016-12-06 19:34:26,156 [myid:1] - INFO [Thread-1137:NIOServerCnxn@1008] - Closed socket connection for client /127.0.0.1:52749 (no session established for client)
2016-12-06 19:34:26,222 [myid:1] - INFO [NIOServerCxn.Factory:0.0.0.0/0.0.0.0:2181:NIOServerCnxnFactory@192] - Accepted socket connection from /127.0.0.1:52750
2016-12-06 19:34:26,222 [myid:1] - INFO [NIOServerCxn.Factory:0.0.0.0/0.0.0.0:2181:NIOServerCnxn@827] - Processing ruok command from /127.0.0.1:52750
2016-12-06 19:34:26,226 [myid:1] - INFO [Thread-1138:NIOServerCnxn@1008] - Closed socket connection for client /127.0.0.1:52750 (no session established for client)
2016-12-06 19:34:36,151 [myid:1] - INFO [NIOServerCxn.Factory:0.0.0.0/0.0.0.0:2181:NIOServerCnxnFactory@192] - Accepted socket connection from /127.0.0.1:52760
2016-12-06 19:34:36,152 [myid:1] - INFO [NIOServerCxn.Factory:0.0.0.0/0.0.0.0:2181:NIOServerCnxn@827] - Processing ruok command from /127.0.0.1:52760
2016-12-06 19:34:36,152 [myid:1] - INFO [Thread-1139:NIOServerCnxn@1008] - Closed socket connection for client /127.0.0.1:52760 (no session established for client)
2016-12-06 19:34:36,230 [myid:1] - INFO [NIOServerCxn.Factory:0.0.0.0/0.0.0.0:2181:NIOServerCnxnFactory@192] - Accepted socket connection from /127.0.0.1:52761
2016-12-06 19:34:36,231 [myid:1] - INFO [NIOServerCxn.Factory:0.0.0.0/0.0.0.0:2181:NIOServerCnxn@827] - Processing ruok command from /127.0.0.1:52761
2016-12-06 19:34:36,231 [myid:1] - INFO [Thread-1140:NIOServerCnxn@1008] - Closed socket connection for client /127.0.0.1:52761 (no session established for client)
2016-12-06 19:34:46,149 [myid:1] - INFO [NIOServerCxn.Factory:0.0.0.0/0.0.0.0:2181:NIOServerCnxnFactory@192] - Accepted socket connection from /127.0.0.1:52767
2016-12-06 19:34:46,149 [myid:1] - INFO [NIOServerCxn.Factory:0.0.0.0/0.0.0.0:2181:NIOServerCnxn@827] - Processing ruok command from /127.0.0.1:52767
2016-12-06 19:34:46,149 [myid:1] - INFO [Thread-1141:NIOServerCnxn@1008] - Closed socket connection for client /127.0.0.1:52767 (no session established for client)
2016-12-06 19:34:46,230 [myid:1] - INFO [NIOServerCxn.Factory:0.0.0.0/0.0.0.0:2181:NIOServerCnxnFactory@192] - Accepted socket connection from /127.0.0.1:52768
2016-12-06 19:34:46,230 [myid:1] - INFO [NIOServerCxn.Factory:0.0.0.0/0.0.0.0:2181:NIOServerCnxn@827] - Processing ruok command from /127.0.0.1:52768
2016-12-06 19:34:46,230 [myid:1] - INFO [Thread-1142:NIOServerCnxn@1008] - Closed socket connection for client /127.0.0.1:52768 (no session established for client)
Kubernetes 支持与多种日志方案集成。你可以选择一个最适合你的集群和应用
的日志解决方案。对于集群级别的日志输出与整合,可以考虑部署一个
边车容器
来轮转和提供日志数据。
配置非特权用户 在容器中允许应用以特权用户运行这条最佳实践是值得商讨的。
如果你的组织要求应用以非特权用户运行,你可以使用
SecurityContext
控制运行容器入口点所使用的用户。
zk StatefulSet 的 Pod 的 template 包含了一个 SecurityContext。
securityContext :
runAsUser : 1000
fsGroup : 1000
在 Pods 的容器内部,UID 1000 对应用户 zookeeper,GID 1000 对应用户组 zookeeper。
从 zk-0 Pod 获取 ZooKeeper 进程信息。
kubectl exec zk-0 -- ps -elf
由于 securityContext 对象的 runAsUser 字段被设置为 1000 而不是 root,
ZooKeeper 进程将以 zookeeper 用户运行。
F S UID PID PPID C PRI NI ADDR SZ WCHAN STIME TTY TIME CMD
4 S zookeep+ 1 0 0 80 0 - 1127 - 20:46 ? 00:00:00 sh -c zkGenConfig.sh && zkServer.sh start-foreground
0 S zookeep+ 27 1 0 80 0 - 1155556 - 20:46 ? 00:00:19 /usr/lib/jvm/java-8-openjdk-amd64/bin/java -Dzookeeper.log.dir=/var/log/zookeeper -Dzookeeper.root.logger=INFO,CONSOLE -cp /usr/bin/../build/classes:/usr/bin/../build/lib/*.jar:/usr/bin/../share/zookeeper/zookeeper-3.4.9.jar:/usr/bin/../share/zookeeper/slf4j-log4j12-1.6.1.jar:/usr/bin/../share/zookeeper/slf4j-api-1.6.1.jar:/usr/bin/../share/zookeeper/netty-3.10.5.Final.jar:/usr/bin/../share/zookeeper/log4j-1.2.16.jar:/usr/bin/../share/zookeeper/jline-0.9.94.jar:/usr/bin/../src/java/lib/*.jar:/usr/bin/../etc/zookeeper: -Xmx2G -Xms2G -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.local.only=false org.apache.zookeeper.server.quorum.QuorumPeerMain /usr/bin/../etc/zookeeper/zoo.cfg
默认情况下,当 Pod 的 PersistentVolume 被挂载到 ZooKeeper 服务器的数据目录时,
它只能被 root 用户访问。这个配置将阻止 ZooKeeper 进程写入它的 WAL 及保存快照。
在 zk-0 Pod 上获取 ZooKeeper 数据目录的文件权限。
kubectl exec -ti zk-0 -- ls -ld /var/lib/zookeeper/data
由于 securityContext 对象的 fsGroup 字段设置为 1000,Pods 的
PersistentVolumes 的所有权属于 zookeeper 用户组,因而 ZooKeeper
进程能够成功地读写数据。
drwxr-sr-x 3 zookeeper zookeeper 4096 Dec 5 20:45 /var/lib/zookeeper/data
管理 ZooKeeper 进程 ZooKeeper 文档
指出“你将需要一个监管程序用于管理每个 ZooKeeper 服务进程(JVM)”。
在分布式系统中,使用一个看门狗(监管程序)来重启故障进程是一种常用的模式。
更新 Ensemble zk StatefulSet 的更新策略被设置为了 RollingUpdate。
你可以使用 kubectl patch 更新分配给每个服务器的 cpus 的数量。
kubectl patch sts zk --type= 'json' -p= '[{"op": "replace", "path": "/spec/template/spec/containers/0/resources/requests/cpu", "value":"0.3"}]'
statefulset.apps/zk patched
使用 kubectl rollout status 观测更新状态。
kubectl rollout status sts/zk
waiting for statefulset rolling update to complete 0 pods at revision zk-5db4499664...
Waiting for 1 pods to be ready...
Waiting for 1 pods to be ready...
waiting for statefulset rolling update to complete 1 pods at revision zk-5db4499664...
Waiting for 1 pods to be ready...
Waiting for 1 pods to be ready...
waiting for statefulset rolling update to complete 2 pods at revision zk-5db4499664...
Waiting for 1 pods to be ready...
Waiting for 1 pods to be ready...
statefulset rolling update complete 3 pods at revision zk-5db4499664...
这项操作会逆序地依次终止每一个 Pod,并用新的配置重新创建。
这样做确保了在滚动更新的过程中 quorum 依旧保持工作。
使用 kubectl rollout history 命令查看历史或先前的配置。
kubectl rollout history sts/zk
statefulsets "zk"
REVISION
1
2
使用 kubectl rollout undo 命令撤销这次的改动。
kubectl rollout undo sts/zk
statefulset.apps/zk rolled back
处理进程故障 重启策略
控制 Kubernetes 如何处理一个 Pod 中容器入口点的进程故障。
对于 StatefulSet 中的 Pods 来说,Always 是唯一合适的 RestartPolicy,也是默认值。
你应该绝不 覆盖有状态应用的默认策略。
检查 zk-0 Pod 中运行的 ZooKeeper 服务器的进程树。
kubectl exec zk-0 -- ps -ef
作为容器入口点的命令的 PID 为 1,Zookeeper 进程是入口点的子进程,
PID 为 27。
UID PID PPID C STIME TTY TIME CMD
zookeep+ 1 0 0 15:03 ? 00:00:00 sh -c zkGenConfig.sh && zkServer.sh start-foreground
zookeep+ 27 1 0 15:03 ? 00:00:03 /usr/lib/jvm/java-8-openjdk-amd64/bin/java -Dzookeeper.log.dir=/var/log/zookeeper -Dzookeeper.root.logger=INFO,CONSOLE -cp /usr/bin/../build/classes:/usr/bin/../build/lib/*.jar:/usr/bin/../share/zookeeper/zookeeper-3.4.9.jar:/usr/bin/../share/zookeeper/slf4j-log4j12-1.6.1.jar:/usr/bin/../share/zookeeper/slf4j-api-1.6.1.jar:/usr/bin/../share/zookeeper/netty-3.10.5.Final.jar:/usr/bin/../share/zookeeper/log4j-1.2.16.jar:/usr/bin/../share/zookeeper/jline-0.9.94.jar:/usr/bin/../src/java/lib/*.jar:/usr/bin/../etc/zookeeper: -Xmx2G -Xms2G -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.local.only=false org.apache.zookeeper.server.quorum.QuorumPeerMain /usr/bin/../etc/zookeeper/zoo.cfg
在一个终端观察 zk StatefulSet 中的 Pods。
kubectl get pod -w -l app = zk
在另一个终端杀掉 Pod zk-0 中的 ZooKeeper 进程。
kubectl exec zk-0 -- pkill java
ZooKeeper 进程的终结导致了它父进程的终止。由于容器的 RestartPolicy
是 Always,父进程被重启。
NAME READY STATUS RESTARTS AGE
zk-0 1/1 Running 0 21m
zk-1 1/1 Running 0 20m
zk-2 1/1 Running 0 19m
NAME READY STATUS RESTARTS AGE
zk-0 0/1 Error 0 29m
zk-0 0/1 Running 1 29m
zk-0 1/1 Running 1 29m
如果你的应用使用一个脚本(例如 zkServer.sh)来启动一个实现了应用业务逻辑的进程,
这个脚本必须和子进程一起结束。这保证了当实现应用业务逻辑的进程故障时,
Kubernetes 会重启这个应用的容器。
存活性测试 你的应用配置为自动重启故障进程,但这对于保持一个分布式系统的健康来说是不够的。
许多场景下,一个系统进程可以是活动状态但不响应请求,或者是不健康状态。
你应该使用存活性探针来通知 Kubernetes 你的应用进程处于不健康状态,需要被重启。
zk StatefulSet 的 Pod 的 template 一节指定了一个存活探针。
livenessProbe :
exec :
command :
- sh
- -c
- "zookeeper-ready 2181"
initialDelaySeconds : 15
timeoutSeconds : 5
这个探针调用一个简单的 Bash 脚本,使用 ZooKeeper 的四字缩写 ruok
来测试服务器的健康状态。
OK=$(echo ruok | nc 127.0.0.1 $1)
if [ "$OK" == "imok" ]; then
exit 0
else
exit 1
fi
在一个终端窗口中使用下面的命令观察 zk StatefulSet 中的 Pods。
kubectl get pod -w -l app = zk
在另一个窗口中,从 Pod zk-0 的文件系统中删除 zookeeper-ready 脚本。
kubectl exec zk-0 -- rm /usr/bin/zookeeper-ready
当 ZooKeeper 进程的存活探针探测失败时,Kubernetes 将会为你自动重启这个进程,
从而保证 ensemble 中不健康状态的进程都被重启。
kubectl get pod -w -l app = zk
NAME READY STATUS RESTARTS AGE
zk-0 1/1 Running 0 1h
zk-1 1/1 Running 0 1h
zk-2 1/1 Running 0 1h
NAME READY STATUS RESTARTS AGE
zk-0 0/1 Running 0 1h
zk-0 0/1 Running 1 1h
zk-0 1/1 Running 1 1h
就绪性测试 就绪不同于存活。如果一个进程是存活的,它是可调度和健康的。
如果一个进程是就绪的,它应该能够处理输入。存活是就绪的必要非充分条件。
在许多场景下,特别是初始化和终止过程中,一个进程可以是存活但没有就绪的。
如果你指定了一个就绪探针,Kubernetes 将保证在就绪检查通过之前,
你的应用不会接收到网络流量。
对于一个 ZooKeeper 服务器来说,存活即就绪。
因此 zookeeper.yaml 清单中的就绪探针和存活探针完全相同。
readinessProbe :
exec :
command :
- sh
- -c
- "zookeeper-ready 2181"
initialDelaySeconds : 15
timeoutSeconds : 5
虽然存活探针和就绪探针是相同的,但同时指定它们两者仍然重要。
这保证了 ZooKeeper ensemble 中只有健康的服务器能接收网络流量。
容忍节点故障 ZooKeeper 需要一个 quorum 来提交数据变动。对于一个拥有 3 个服务器的 ensemble 来说,
必须有两个服务器是健康的,写入才能成功。
在基于 quorum 的系统里,成员被部署在多个故障域中以保证可用性。
为了防止由于某台机器断连引起服务中断,最佳实践是防止应用的多个实例在相同的机器上共存。
默认情况下,Kubernetes 可以把 StatefulSet 的 Pods 部署在相同节点上。
对于你创建的 3 个服务器的 ensemble 来说,如果有两个服务器并存于
相同的节点上并且该节点发生故障时,ZooKeeper 服务将中断,
直至至少一个 Pods 被重新调度。
你应该总是提供多余的容量以允许关键系统进程在节点故障时能够被重新调度。
如果你这样做了,服务故障就只会持续到 Kubernetes 调度器重新调度某个
ZooKeeper 服务器为止。
但是,如果希望你的服务在容忍节点故障时无停服时间,你应该设置 podAntiAffinity。
获取 zk Stateful Set 中的 Pods 的节点。
for i in 0 1 2; do kubectl get pod zk-$i --template {{ .spec.nodeName}} ; echo "" ; done
zk StatefulSet 中所有的 Pods 都被部署在不同的节点。
kubernetes-node-cxpk
kubernetes-node-a5aq
kubernetes-node-2g2d
这是因为 zk StatefulSet 中的 Pods 指定了 PodAntiAffinity。
affinity :
podAntiAffinity :
requiredDuringSchedulingIgnoredDuringExecution :
- labelSelector :
matchExpressions :
- key : "app"
operator : In
values :
- zk
topologyKey : "kubernetes.io/hostname"
requiredDuringSchedulingIgnoredDuringExecution 告诉 Kubernetes 调度器,
在以 topologyKey 指定的域中,绝对不要把带有键为 app、值为 zk 的标签
的两个 Pods 调度到相同的节点。topologyKey kubernetes.io/hostname 表示
这个域是一个单独的节点。
使用不同的规则、标签和选择算符,你能够通过这种技术把你的 ensemble 分布
在不同的物理、网络和电力故障域之间。
节点维护期间保持应用可用 在本节中你将会隔离(Cordon)和腾空(Drain)节点。
如果你是在一个共享的集群里使用本教程,请保证不会影响到其他租户。
上一小节展示了如何在节点之间分散 Pods 以在计划外的节点故障时保证服务存活。
但是你也需要为计划内维护引起的临时节点故障做准备。
使用此命令获取你的集群中的节点。
使用 kubectl cordon
隔离你的集群中除 4 个节点以外的所有节点。
kubectl cordon <node-name>
使用下面的命令获取 zk-pdb PodDisruptionBudget。
max-unavailable 字段指示 Kubernetes 在任何时候,zk StatefulSet
至多有一个 Pod 是不可用的。
NAME MIN-AVAILABLE MAX-UNAVAILABLE ALLOWED-DISRUPTIONS AGE
zk-pdb N/A 1 1
在一个终端中,使用下面的命令观察 zk StatefulSet 中的 Pods。
kubectl get pods -w -l app = zk
在另一个终端中,使用下面的命令获取 Pods 当前调度的节点。
for i in 0 1 2; do kubectl get pod zk-$i --template {{ .spec.nodeName}} ; echo "" ; done
kubernetes-node-pb41
kubernetes-node-ixsl
kubernetes-node-i4c4
使用 kubectl drain
来隔离和腾空 zk-0 Pod 调度所在的节点。
kubectl drain $( kubectl get pod zk-0 --template {{ .spec.nodeName}} ) --ignore-daemonsets --force --delete-local-data
node "kubernetes-node-pb41" cordoned
WARNING: Deleting pods not managed by ReplicationController, ReplicaSet, Job, or DaemonSet: fluentd-cloud-logging-kubernetes-node-pb41, kube-proxy-kubernetes-node-pb41; Ignoring DaemonSet-managed pods: node-problem-detector-v0.1-o5elz
pod "zk-0" deleted
node "kubernetes-node-pb41" drained
由于你的集群中有 4 个节点, kubectl drain 执行成功,zk-0 被调度到其它节点。
NAME READY STATUS RESTARTS AGE
zk-0 1/1 Running 2 1h
zk-1 1/1 Running 0 1h
zk-2 1/1 Running 0 1h
NAME READY STATUS RESTARTS AGE
zk-0 1/1 Terminating 2 2h
zk-0 0/1 Terminating 2 2h
zk-0 0/1 Terminating 2 2h
zk-0 0/1 Terminating 2 2h
zk-0 0/1 Pending 0 0s
zk-0 0/1 Pending 0 0s
zk-0 0/1 ContainerCreating 0 0s
zk-0 0/1 Running 0 51s
zk-0 1/1 Running 0 1m
在第一个终端中持续观察 StatefulSet 的 Pods 并腾空 zk-1 调度所在的节点。
kubectl drain $( kubectl get pod zk-1 --template {{ .spec.nodeName}} ) --ignore-daemonsets --force --delete-local-data "kubernetes-node-ixsl" cordoned
WARNING: Deleting pods not managed by ReplicationController, ReplicaSet, Job, or DaemonSet: fluentd-cloud-logging-kubernetes-node-ixsl, kube-proxy-kubernetes-node-ixsl; Ignoring DaemonSet-managed pods: node-problem-detector-v0.1-voc74
pod "zk-1" deleted
node "kubernetes-node-ixsl" drained
zk-1 Pod 不能被调度,这是因为 zk StatefulSet 包含了一个防止 Pods
共存的 PodAntiAffinity 规则,而且只有两个节点可用于调度,
这个 Pod 将保持在 Pending 状态。
kubectl get pods -w -l app = zk
NAME READY STATUS RESTARTS AGE
zk-0 1/1 Running 2 1h
zk-1 1/1 Running 0 1h
zk-2 1/1 Running 0 1h
NAME READY STATUS RESTARTS AGE
zk-0 1/1 Terminating 2 2h
zk-0 0/1 Terminating 2 2h
zk-0 0/1 Terminating 2 2h
zk-0 0/1 Terminating 2 2h
zk-0 0/1 Pending 0 0s
zk-0 0/1 Pending 0 0s
zk-0 0/1 ContainerCreating 0 0s
zk-0 0/1 Running 0 51s
zk-0 1/1 Running 0 1m
zk-1 1/1 Terminating 0 2h
zk-1 0/1 Terminating 0 2h
zk-1 0/1 Terminating 0 2h
zk-1 0/1 Terminating 0 2h
zk-1 0/1 Pending 0 0s
zk-1 0/1 Pending 0 0s
继续观察 StatefulSet 中的 Pods 并腾空 zk-2 调度所在的节点。
kubectl drain $( kubectl get pod zk-2 --template {{ .spec.nodeName}} ) --ignore-daemonsets --force --delete-local-data
node "kubernetes-node-i4c4" cordoned
WARNING: Deleting pods not managed by ReplicationController, ReplicaSet, Job, or DaemonSet: fluentd-cloud-logging-kubernetes-node-i4c4, kube-proxy-kubernetes-node-i4c4; Ignoring DaemonSet-managed pods: node-problem-detector-v0.1-dyrog
WARNING: Ignoring DaemonSet-managed pods: node-problem-detector-v0.1-dyrog; Deleting pods not managed by ReplicationController, ReplicaSet, Job, or DaemonSet: fluentd-cloud-logging-kubernetes-node-i4c4, kube-proxy-kubernetes-node-i4c4
There are pending pods when an error occurred: Cannot evict pod as it would violate the pod's disruption budget.
pod/zk-2
使用 CRTL-C 终止 kubectl。
你不能腾空第三个节点,因为驱逐 zk-2 将和 zk-budget 冲突。
然而这个节点仍然处于隔离状态(Cordoned)。
使用 zkCli.sh 从 zk-0 取回你的健康检查中输入的数值。
kubectl exec zk-0 zkCli.sh get /hello
由于遵守了 PodDisruptionBudget,服务仍然可用。
WatchedEvent state:SyncConnected type:None path:null
world
cZxid = 0x200000002
ctime = Wed Dec 07 00:08:59 UTC 2016
mZxid = 0x200000002
mtime = Wed Dec 07 00:08:59 UTC 2016
pZxid = 0x200000002
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 5
numChildren = 0
使用 kubectl uncordon
来取消对第一个节点的隔离。
kubectl uncordon kubernetes-node-pb41
node "kubernetes-node-pb41" uncordoned
zk-1 被重新调度到了这个节点。等待 zk-1 变为 Running 和 Ready 状态。
kubectl get pods -w -l app = zk
NAME READY STATUS RESTARTS AGE
zk-0 1/1 Running 2 1h
zk-1 1/1 Running 0 1h
zk-2 1/1 Running 0 1h
NAME READY STATUS RESTARTS AGE
zk-0 1/1 Terminating 2 2h
zk-0 0/1 Terminating 2 2h
zk-0 0/1 Terminating 2 2h
zk-0 0/1 Terminating 2 2h
zk-0 0/1 Pending 0 0s
zk-0 0/1 Pending 0 0s
zk-0 0/1 ContainerCreating 0 0s
zk-0 0/1 Running 0 51s
zk-0 1/1 Running 0 1m
zk-1 1/1 Terminating 0 2h
zk-1 0/1 Terminating 0 2h
zk-1 0/1 Terminating 0 2h
zk-1 0/1 Terminating 0 2h
zk-1 0/1 Pending 0 0s
zk-1 0/1 Pending 0 0s
zk-1 0/1 Pending 0 12m
zk-1 0/1 ContainerCreating 0 12m
zk-1 0/1 Running 0 13m
zk-1 1/1 Running 0 13m
尝试腾空 zk-2 调度所在的节点。
kubectl drain $( kubectl get pod zk-2 --template {{ .spec.nodeName}} ) --ignore-daemonsets --force --delete-local-data
输出:
node "kubernetes-node-i4c4" already cordoned
WARNING: Deleting pods not managed by ReplicationController, ReplicaSet, Job, or DaemonSet: fluentd-cloud-logging-kubernetes-node-i4c4, kube-proxy-kubernetes-node-i4c4; Ignoring DaemonSet-managed pods: node-problem-detector-v0.1-dyrog
pod "heapster-v1.2.0-2604621511-wht1r" deleted
pod "zk-2" deleted
node "kubernetes-node-i4c4" drained
这次 kubectl drain 执行成功。
取消第二个节点的隔离,以允许 zk-2 被重新调度。
kubectl uncordon kubernetes-node-ixsl
node "kubernetes-node-ixsl" uncordoned
你可以同时使用 kubectl drain 和 PodDisruptionBudgets 来保证你的服务
在维护过程中仍然可用。如果使用了腾空操作来隔离节点并在节点离线之前驱逐了 pods,
那么设置了干扰预算的服务将会遵守该预算。
你应该总是为关键服务分配额外容量,这样它们的 Pods 就能够迅速的重新调度。
清理现场 使用 kubectl uncordon 解除你集群中所有节点的隔离。 你需要删除在本教程中使用的 PersistentVolumes 的持久存储媒介。
请遵循必须的步骤,基于你的环境、存储配置和制备方法,保证回收所有的存储。 5.5.3 - StatefulSet 基础 本教程介绍如何了使用 StatefulSets 来管理应用。演示了如何创建、删除、扩容/缩容和更新 StatefulSets 的 Pods。
准备开始 在开始本教程之前,你应该熟悉以下 Kubernetes 的概念:
本教程假设你的集群被配置为动态的提供 PersistentVolumes。如果没有这样配置,在开始本教程之前,你需要手动准备 2 个 1 GiB 的存储卷。
教程目标 StatefulSets 旨在与有状态的应用及分布式系统一起使用。然而在 Kubernetes 上管理有状态应用和分布式系统是一个宽泛而复杂的话题。为了演示 StatefulSet 的基本特性,并且不使前后的主题混淆,你将会使用 StatefulSet 部署一个简单的 web 应用。
在阅读本教程后,你将熟悉以下内容:
如何创建 StatefulSet StatefulSet 怎样管理它的 Pods 如何删除 StatefulSet 如何对 StatefulSet 进行扩容/缩容 如何更新一个 StatefulSet 的 Pods 创建 StatefulSet 作为开始,使用如下示例创建一个 StatefulSet。它和 StatefulSets 概念中的示例相似。它创建了一个 Headless Service nginx 用来发布 StatefulSet web 中的 Pod 的 IP 地址。
apiVersion : v1
kind : Service
metadata :
name : nginx
labels :
app : nginx
spec :
ports :
- port : 80
name : web
clusterIP : None
selector :
app : nginx
---
apiVersion : apps/v1
kind : StatefulSet
metadata :
name : web
spec :
serviceName : "nginx"
replicas : 2
selector :
matchLabels :
app : nginx
template :
metadata :
labels :
app : nginx
spec :
containers :
- name : nginx
image : k8s.gcr.io/nginx-slim:0.8
ports :
- containerPort : 80
name : web
volumeMounts :
- name : www
mountPath : /usr/share/nginx/html
volumeClaimTemplates :
- metadata :
name : www
spec :
accessModes : [ "ReadWriteOnce" ]
resources :
requests :
storage : 1Gi
下载上面的例子并保存为文件 web.yaml。
你需要使用两个终端窗口。在第一个终端中,使用 kubectl get 来查看 StatefulSet 的 Pods 的创建情况。
kubectl get pods -w -l app = nginx
在另一个终端中,使用 kubectl apply 来创建定义在 web.yaml 中的 Headless Service 和 StatefulSet。
kubectl apply -f web.yaml
service/nginx created
statefulset.apps/web created
上面的命令创建了两个 Pod,每个都运行了一个 NGINX web 服务器。获取 nginx Service 和 web StatefulSet 来验证是否成功的创建了它们。
kubectl get service nginx
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT( S) AGE
nginx ClusterIP None <none> 80/TCP 12s
kubectl get statefulset web
NAME DESIRED CURRENT AGE
web 2 1 20s
顺序创建 Pod 对于一个拥有 N 个副本的 StatefulSet,Pod 被部署时是按照 {0 …… N-1} 的序号顺序创建的。在第一个终端中使用 kubectl get 检查输出。这个输出最终将看起来像下面的样子。
kubectl get pods -w -l app = nginx
NAME READY STATUS RESTARTS AGE
web-0 0/1 Pending 0 0s
web-0 0/1 Pending 0 0s
web-0 0/1 ContainerCreating 0 0s
web-0 1/1 Running 0 19s
web-1 0/1 Pending 0 0s
web-1 0/1 Pending 0 0s
web-1 0/1 ContainerCreating 0 0s
web-1 1/1 Running 0 18s
请注意在 web-0 Pod 处于 Running和Ready 状态后 web-1 Pod 才会被启动。
StatefulSet 中的 Pod StatefulSet 中的 Pod 拥有一个唯一的顺序索引和稳定的网络身份标识。
检查 Pod 的顺序索引 获取 StatefulSet 的 Pod。
kubectl get pods -l app = nginx
NAME READY STATUS RESTARTS AGE
web-0 1/1 Running 0 1m
web-1 1/1 Running 0 1m
如同 StatefulSets 概念中所提到的,StatefulSet 中的 Pod 拥有一个具有黏性的、独一无二的身份标志。这个标志基于 StatefulSet 控制器分配给每个 Pod 的唯一顺序索引。Pod 的名称的形式为<statefulset name>-<ordinal index>。webStatefulSet 拥有两个副本,所以它创建了两个 Pod:web-0和web-1。
使用稳定的网络身份标识 每个 Pod 都拥有一个基于其顺序索引的稳定的主机名。使用kubectl exec 在每个 Pod 中执行hostname。
for i in 0 1; do kubectl exec web-$i -- sh -c 'hostname' ; done
web-0
web-1
使用 kubectl run 运行一个提供 nslookup 命令的容器,该命令来自于 dnsutils 包。通过对 Pod 的主机名执行 nslookup,你可以检查他们在集群内部的 DNS 地址。
kubectl run -i --tty --image busybox:1.28 dns-test --restart= Never --rm
nslookup web-0.nginx
Server: 10.0.0.10
Address 1: 10.0.0.10 kube-dns.kube-system.svc.cluster.local
Name: web-0.nginx
Address 1: 10.244.1.6
nslookup web-1.nginx
Server: 10.0.0.10
Address 1: 10.0.0.10 kube-dns.kube-system.svc.cluster.local
Name: web-1.nginx
Address 1: 10.244.2.6
headless service 的 CNAME 指向 SRV 记录(记录每个 Running 和 Ready 状态的 Pod)。SRV 记录指向一个包含 Pod IP 地址的记录表项。
在一个终端中查看 StatefulSet 的 Pod。
kubectl get pod -w -l app = nginx
在另一个终端中使用 kubectl delete 删除 StatefulSet 中所有的 Pod。
kubectl delete pod -l app = nginx
pod "web-0" deleted
pod "web-1" deleted
等待 StatefulSet 重启它们,并且两个 Pod 都变成 Running 和 Ready 状态。
kubectl get pod -w -l app = nginx
NAME READY STATUS RESTARTS AGE
web-0 0/1 ContainerCreating 0 0s
NAME READY STATUS RESTARTS AGE
web-0 1/1 Running 0 2s
web-1 0/1 Pending 0 0s
web-1 0/1 Pending 0 0s
web-1 0/1 ContainerCreating 0 0s
web-1 1/1 Running 0 34s
使用 kubectl exec 和 kubectl run 查看 Pod 的主机名和集群内部的 DNS 表项。
for i in 0 1; do kubectl exec web-$i -- sh -c 'hostname' ; done
web-0
web-1
kubectl run -i --tty --image busybox:1.28 dns-test --restart= Never --rm /bin/sh
nslookup web-0.nginx
Server: 10.0.0.10
Address 1: 10.0.0.10 kube-dns.kube-system.svc.cluster.local
Name: web-0.nginx
Address 1: 10.244.1.7
nslookup web-1.nginx
Server: 10.0.0.10
Address 1: 10.0.0.10 kube-dns.kube-system.svc.cluster.local
Name: web-1.nginx
Address 1: 10.244.2.8
Pod 的序号、主机名、SRV 条目和记录名称没有改变,但和 Pod 相关联的 IP 地址可能发生了改变。在本教程中使用的集群中它们就改变了。这就是为什么不要在其他应用中使用 StatefulSet 中的 Pod 的 IP 地址进行连接,这点很重要。
如果你需要查找并连接一个 StatefulSet 的活动成员,你应该查询 Headless Service 的 CNAME。和 CNAME 相关联的 SRV 记录只会包含 StatefulSet 中处于 Running 和 Ready 状态的 Pod。
如果你的应用已经实现了用于测试 liveness 和 readiness 的连接逻辑,你可以使用 Pod 的 SRV 记录(web-0.nginx.default.svc.cluster.local,
web-1.nginx.default.svc.cluster.local)。因为他们是稳定的,并且当你的 Pod 的状态变为 Running 和 Ready 时,你的应用就能够发现它们的地址。
写入稳定的存储 获取 web-0 和 web-1 的 PersistentVolumeClaims。
kubectl get pvc -l app = nginx
NAME STATUS VOLUME CAPACITY ACCESSMODES AGE
www-web-0 Bound pvc-15c268c7-b507-11e6-932f-42010a800002 1Gi RWO 48s
www-web-1 Bound pvc-15c79307-b507-11e6-932f-42010a800002 1Gi RWO 48s
StatefulSet 控制器创建了两个 PersistentVolumeClaims,绑定到两个 PersistentVolumes 。由于本教程使用的集群配置为动态提供 PersistentVolume,所有的 PersistentVolume 都是自动创建和绑定的。
NGINX web 服务器默认会加载位于 /usr/share/nginx/html/index.html 的 index 文件。StatefulSets spec 中的 volumeMounts 字段保证了 /usr/share/nginx/html 文件夹由一个 PersistentVolume 支持。
将 Pod 的主机名写入它们的index.html文件并验证 NGINX web 服务器使用该主机名提供服务。
for i in 0 1; do kubectl exec web-$i -- sh -c 'echo $(hostname) > /usr/share/nginx/html/index.html' ; done
for i in 0 1; do kubectl exec -it web-$i -- curl localhost; done
web-0
web-1
说明: 请注意,如果你看见上面的 curl 命令返回了 403 Forbidden 的响应,你需要像这样修复使用 volumeMounts(due to a bug when using hostPath volumes )挂载的目录的权限:
for i in 0 1; do kubectl exec web-$i -- chmod 755 /usr/share/nginx/html; done
在你重新尝试上面的 curl 命令之前。
在一个终端查看 StatefulSet 的 Pod。
kubectl get pod -w -l app = nginx
在另一个终端删除 StatefulSet 所有的 Pod。
kubectl delete pod -l app = nginx
pod "web-0" deleted
pod "web-1" deleted
在第一个终端里检查 kubectl get 命令的输出,等待所有 Pod 变成 Running 和 Ready 状态。
kubectl get pod -w -l app = nginx
NAME READY STATUS RESTARTS AGE
web-0 0/1 ContainerCreating 0 0s
NAME READY STATUS RESTARTS AGE
web-0 1/1 Running 0 2s
web-1 0/1 Pending 0 0s
web-1 0/1 Pending 0 0s
web-1 0/1 ContainerCreating 0 0s
web-1 1/1 Running 0 34s
验证所有 web 服务器在继续使用它们的主机名提供服务。
for i in 0 1; do kubectl exec -it web-$i -- curl localhost; done
web-0
web-1
虽然 web-0 和 web-1 被重新调度了,但它们仍然继续监听各自的主机名,因为和它们的 PersistentVolumeClaim 相关联的 PersistentVolume 被重新挂载到了各自的 volumeMount 上。不管 web-0 和 web-1 被调度到了哪个节点上,它们的 PersistentVolumes 将会被挂载到合适的挂载点上。
扩容/缩容 StatefulSet 扩容/缩容 StatefulSet 指增加或减少它的副本数。这通过更新 replicas 字段完成。你可以使用kubectl scale 或者kubectl patch 来扩容/缩容一个 StatefulSet。
扩容 在一个终端窗口观察 StatefulSet 的 Pod。
kubectl get pods -w -l app = nginx
在另一个终端窗口使用 kubectl scale 扩展副本数为 5。
kubectl scale sts web --replicas= 5
statefulset.apps/web scaled
在第一个 终端中检查 kubectl get 命令的输出,等待增加的 3 个 Pod 的状态变为 Running 和 Ready。
kubectl get pods -w -l app = nginx
NAME READY STATUS RESTARTS AGE
web-0 1/1 Running 0 2h
web-1 1/1 Running 0 2h
NAME READY STATUS RESTARTS AGE
web-2 0/1 Pending 0 0s
web-2 0/1 Pending 0 0s
web-2 0/1 ContainerCreating 0 0s
web-2 1/1 Running 0 19s
web-3 0/1 Pending 0 0s
web-3 0/1 Pending 0 0s
web-3 0/1 ContainerCreating 0 0s
web-3 1/1 Running 0 18s
web-4 0/1 Pending 0 0s
web-4 0/1 Pending 0 0s
web-4 0/1 ContainerCreating 0 0s
web-4 1/1 Running 0 19s
StatefulSet 控制器扩展了副本的数量。如同创建 StatefulSet 所述,StatefulSet 按序号索引顺序的创建每个 Pod,并且会等待前一个 Pod 变为 Running 和 Ready 才会启动下一个 Pod。
缩容 在一个终端观察 StatefulSet 的 Pod。
kubectl get pods -w -l app = nginx
在另一个终端使用 kubectl patch 将 StatefulSet 缩容回三个副本。
kubectl patch sts web -p '{"spec":{"replicas":3}}'
statefulset.apps/web patched
等待 web-4 和 web-3 状态变为 Terminating。
kubectl get pods -w -l app=nginx
NAME READY STATUS RESTARTS AGE
web-0 1/1 Running 0 3h
web-1 1/1 Running 0 3h
web-2 1/1 Running 0 55s
web-3 1/1 Running 0 36s
web-4 0/1 ContainerCreating 0 18s
NAME READY STATUS RESTARTS AGE
web-4 1/1 Running 0 19s
web-4 1/1 Terminating 0 24s
web-4 1/1 Terminating 0 24s
web-3 1/1 Terminating 0 42s
web-3 1/1 Terminating 0 42s
顺序终止 Pod 控制器会按照与 Pod 序号索引相反的顺序每次删除一个 Pod。在删除下一个 Pod 前会等待上一个被完全关闭。
获取 StatefulSet 的 PersistentVolumeClaims。
kubectl get pvc -l app = nginx
NAME STATUS VOLUME CAPACITY ACCESSMODES AGE
www-web-0 Bound pvc-15c268c7-b507-11e6-932f-42010a800002 1Gi RWO 13h
www-web-1 Bound pvc-15c79307-b507-11e6-932f-42010a800002 1Gi RWO 13h
www-web-2 Bound pvc-e1125b27-b508-11e6-932f-42010a800002 1Gi RWO 13h
www-web-3 Bound pvc-e1176df6-b508-11e6-932f-42010a800002 1Gi RWO 13h
www-web-4 Bound pvc-e11bb5f8-b508-11e6-932f-42010a800002 1Gi RWO 13h
五个 PersistentVolumeClaims 和五个 PersistentVolumes 仍然存在。查看 Pod 的 稳定存储 ,我们发现当删除 StatefulSet 的 Pod 时,挂载到 StatefulSet 的 Pod 的 PersistentVolumes 不会被删除。当这种删除行为是由 StatefulSet 缩容引起时也是一样的。
更新 StatefulSet Kubernetes 1.7 版本的 StatefulSet 控制器支持自动更新。更新策略由 StatefulSet API Object 的spec.updateStrategy 字段决定。这个特性能够用来更新一个 StatefulSet 中的 Pod 的 container images,resource requests,以及 limits,labels 和 annotations。RollingUpdate滚动更新是 StatefulSets 默认策略。
Rolling Update 策略 RollingUpdate 更新策略会更新一个 StatefulSet 中所有的 Pod,采用与序号索引相反的顺序并遵循 StatefulSet 的保证。
Patch web StatefulSet 来执行 RollingUpdate 更新策略。
kubectl patch statefulset web -p '{"spec":{"updateStrategy":{"type":"RollingUpdate"}}}'
statefulset.apps/web patched
在一个终端窗口中 patch web StatefulSet 来再次的改变容器镜像。
kubectl patch statefulset web --type= 'json' -p= '[{"op": "replace", "path": "/spec/template/spec/containers/0/image", "value":"gcr.io/google_containers/nginx-slim:0.8"}]'
statefulset.apps/web patched
在另一个终端监控 StatefulSet 中的 Pod。
kubectl get po -l app = nginx -w
NAME READY STATUS RESTARTS AGE
web-0 1/1 Running 0 7m
web-1 1/1 Running 0 7m
web-2 1/1 Running 0 8m
web-2 1/1 Terminating 0 8m
web-2 1/1 Terminating 0 8m
web-2 0/1 Terminating 0 8m
web-2 0/1 Terminating 0 8m
web-2 0/1 Terminating 0 8m
web-2 0/1 Terminating 0 8m
web-2 0/1 Pending 0 0s
web-2 0/1 Pending 0 0s
web-2 0/1 ContainerCreating 0 0s
web-2 1/1 Running 0 19s
web-1 1/1 Terminating 0 8m
web-1 0/1 Terminating 0 8m
web-1 0/1 Terminating 0 8m
web-1 0/1 Terminating 0 8m
web-1 0/1 Pending 0 0s
web-1 0/1 Pending 0 0s
web-1 0/1 ContainerCreating 0 0s
web-1 1/1 Running 0 6s
web-0 1/1 Terminating 0 7m
web-0 1/1 Terminating 0 7m
web-0 0/1 Terminating 0 7m
web-0 0/1 Terminating 0 7m
web-0 0/1 Terminating 0 7m
web-0 0/1 Terminating 0 7m
web-0 0/1 Pending 0 0s
web-0 0/1 Pending 0 0s
web-0 0/1 ContainerCreating 0 0s
web-0 1/1 Running 0 10s
StatefulSet 里的 Pod 采用和序号相反的顺序更新。在更新下一个 Pod 前,StatefulSet 控制器终止每个 Pod 并等待它们变成 Running 和 Ready。请注意,虽然在顺序后继者变成 Running 和 Ready 之前 StatefulSet 控制器不会更新下一个 Pod,但它仍然会重建任何在更新过程中发生故障的 Pod,使用的是它们当前的版本。已经接收到更新请求的 Pod 将会被恢复为更新的版本,没有收到请求的 Pod 则会被恢复为之前的版本。像这样,控制器尝试继续使应用保持健康并在出现间歇性故障时保持更新的一致性。
获取 Pod 来查看他们的容器镜像。
for p in 0 1 2; do kubectl get po web-$p --template '{{range $i, $c := .spec.containers}}{{$c.image}}{{end}}' ; echo; done
k8s.gcr.io/nginx-slim:0.8
k8s.gcr.io/nginx-slim:0.8
k8s.gcr.io/nginx-slim:0.8
StatefulSet 中的所有 Pod 现在都在运行之前的容器镜像。
小窍门 :你还可以使用 kubectl rollout status sts/<name> 来查看 rolling update 的状态。
分段更新 你可以使用 RollingUpdate 更新策略的 partition 参数来分段更新一个 StatefulSet。分段的更新将会使 StatefulSet 中的其余所有 Pod 保持当前版本的同时仅允许改变 StatefulSet 的 .spec.template。
Patch web StatefulSet 来对 updateStrategy 字段添加一个分区。
kubectl patch statefulset web -p '{"spec":{"updateStrategy":{"type":"RollingUpdate","rollingUpdate":{"partition":3}}}}'
statefulset.apps/web patched
再次 Patch StatefulSet 来改变容器镜像。
kubectl patch statefulset web --type= 'json' -p= '[{"op": "replace", "path": "/spec/template/spec/containers/0/image", "value":"k8s.gcr.io/nginx-slim:0.7"}]'
statefulset.apps/web patched
删除 StatefulSet 中的 Pod。
kubectl delete po web-2
pod "web-2" deleted
等待 Pod 变成 Running 和 Ready。
kubectl get po -lapp= nginx -w
NAME READY STATUS RESTARTS AGE
web-0 1/1 Running 0 4m
web-1 1/1 Running 0 4m
web-2 0/1 ContainerCreating 0 11s
web-2 1/1 Running 0 18s
获取 Pod 的容器。
kubectl get po web-2 --template '{{range $i, $c := .spec.containers}}{{$c.image}}{{end}}'
k8s.gcr.io/nginx-slim:0.8
请注意,虽然更新策略是 RollingUpdate,StatefulSet 控制器还是会使用原始的容器恢复 Pod。这是因为 Pod 的序号比 updateStrategy 指定的 partition 更小。
灰度发布 你可以通过减少 上文 指定的 partition 来进行灰度发布,以此来测试你的程序的改动。
通过 patch 命令修改 StatefulSet 来减少分区。
kubectl patch statefulset web -p '{"spec":{"updateStrategy":{"type":"RollingUpdate","rollingUpdate":{"partition":2}}}}'
statefulset.apps/web patched
等待 web-2 变成 Running 和 Ready。
kubectl get po -lapp= nginx -w
NAME READY STATUS RESTARTS AGE
web-0 1/1 Running 0 4m
web-1 1/1 Running 0 4m
web-2 0/1 ContainerCreating 0 11s
web-2 1/1 Running 0 18s
获取 Pod 的容器。
kubectl get po web-2 --template '{{range $i, $c := .spec.containers}}{{$c.image}}{{end}}'
k8s.gcr.io/nginx-slim:0.7
当你改变 partition 时,StatefulSet 会自动的更新 web-2 Pod,这是因为 Pod 的序号小于或等于 partition。
删除 web-1 Pod。
kubectl delete po web-1
pod "web-1" deleted
等待 web-1 变成 Running 和 Ready。
kubectl get po -lapp= nginx -w
NAME READY STATUS RESTARTS AGE
web-0 1/1 Running 0 6m
web-1 0/1 Terminating 0 6m
web-2 1/1 Running 0 2m
web-1 0/1 Terminating 0 6m
web-1 0/1 Terminating 0 6m
web-1 0/1 Terminating 0 6m
web-1 0/1 Pending 0 0s
web-1 0/1 Pending 0 0s
web-1 0/1 ContainerCreating 0 0s
web-1 1/1 Running 0 18s
获取 web-1 Pod 的容器。
kubectl get po web-1 --template '{{range $i, $c := .spec.containers}}{{$c.image}}{{end}}'
k8s.gcr.io/nginx-slim:0.8
web-1 被按照原来的配置恢复,因为 Pod 的序号小于分区。当指定了分区时,如果更新了 StatefulSet 的 .spec.template,则所有序号大于或等于分区的 Pod 都将被更新。如果一个序号小于分区的 Pod 被删除或者终止,它将被按照原来的配置恢复。
分阶段的发布 你可以使用类似灰度发布 的方法执行一次分阶段的发布(例如一次线性的、等比的或者指数形式的发布)。要执行一次分阶段的发布,你需要设置 partition 为希望控制器暂停更新的序号。
分区当前为2。请将分区设置为0。
kubectl patch statefulset web -p '{"spec":{"updateStrategy":{"type":"RollingUpdate","rollingUpdate":{"partition":0}}}}'
statefulset.apps/web patched
等待 StatefulSet 中的所有 Pod 变成 Running 和 Ready。
kubectl get po -lapp= nginx -w
NAME READY STATUS RESTARTS AGE
web-0 1/1 Running 0 3m
web-1 0/1 ContainerCreating 0 11s
web-2 1/1 Running 0 2m
web-1 1/1 Running 0 18s
web-0 1/1 Terminating 0 3m
web-0 1/1 Terminating 0 3m
web-0 0/1 Terminating 0 3m
web-0 0/1 Terminating 0 3m
web-0 0/1 Terminating 0 3m
web-0 0/1 Terminating 0 3m
web-0 0/1 Pending 0 0s
web-0 0/1 Pending 0 0s
web-0 0/1 ContainerCreating 0 0s
web-0 1/1 Running 0 3s
获取 Pod 的容器。
for p in 0 1 2; do kubectl get po web-$p --template '{{range $i, $c := .spec.containers}}{{$c.image}}{{end}}' ; echo; done
k8s.gcr.io/nginx-slim:0.7
k8s.gcr.io/nginx-slim:0.7
k8s.gcr.io/nginx-slim:0.7
将 partition 改变为 0 以允许 StatefulSet 控制器继续更新过程。
On Delete 策略 OnDelete 更新策略实现了传统(1.7 之前)行为,它也是默认的更新策略。当你选择这个更新策略并修改 StatefulSet 的 .spec.template 字段时,StatefulSet 控制器将不会自动的更新 Pod。
删除 StatefulSet StatefulSet 同时支持级联和非级联删除。使用非级联方式删除 StatefulSet 时,StatefulSet 的 Pod 不会被删除。使用级联删除时,StatefulSet 和它的 Pod 都会被删除。
非级联删除 在一个终端窗口查看 StatefulSet 中的 Pod。
kubectl get pods -w -l app=nginx
使用 kubectl delete 删除 StatefulSet。请确保提供了 --cascade=false 参数给命令。这个参数告诉 Kubernetes 只删除 StatefulSet 而不要删除它的任何 Pod。
kubectl delete statefulset web --cascade= false
statefulset.apps "web" deleted
获取 Pod 来检查他们的状态。
kubectl get pods -l app = nginx
NAME READY STATUS RESTARTS AGE
web-0 1/1 Running 0 6m
web-1 1/1 Running 0 7m
web-2 1/1 Running 0 5m
虽然 web 已经被删除了,但所有 Pod 仍然处于 Running 和 Ready 状态。
删除 web-0。
kubectl delete pod web-0
pod "web-0" deleted
获取 StatefulSet 的 Pod。
kubectl get pods -l app = nginx
NAME READY STATUS RESTARTS AGE
web-1 1/1 Running 0 10m
web-2 1/1 Running 0 7m
由于 web StatefulSet 已经被删除,web-0没有被重新启动。
在一个终端监控 StatefulSet 的 Pod。
kubectl get pods -w -l app = nginx
在另一个终端里重新创建 StatefulSet。请注意,除非你删除了 nginx Service (你不应该这样做),你将会看到一个错误,提示 Service 已经存在。
kubectl apply -f web.yaml
statefulset.apps/web created
service/nginx unchanged
请忽略这个错误。它仅表示 kubernetes 进行了一次创建 nginx Headless Service 的尝试,尽管那个 Service 已经存在。
在第一个终端中运行并检查 kubectl get 命令的输出。
kubectl get pods -w -l app = nginx
NAME READY STATUS RESTARTS AGE
web-1 1/1 Running 0 16m
web-2 1/1 Running 0 2m
NAME READY STATUS RESTARTS AGE
web-0 0/1 Pending 0 0s
web-0 0/1 Pending 0 0s
web-0 0/1 ContainerCreating 0 0s
web-0 1/1 Running 0 18s
web-2 1/1 Terminating 0 3m
web-2 0/1 Terminating 0 3m
web-2 0/1 Terminating 0 3m
web-2 0/1 Terminating 0 3m
当重新创建 web StatefulSet 时,web-0被第一个重新启动。由于 web-1 已经处于 Running 和 Ready 状态,当 web-0 变成 Running 和 Ready 时,StatefulSet 会直接接收这个 Pod。由于你重新创建的 StatefulSet 的 replicas 等于 2,一旦 web-0 被重新创建并且 web-1 被认为已经处于 Running 和 Ready 状态时,web-2将会被终止。
让我们再看看被 Pod 的 web 服务器加载的 index.html 的内容。
for i in 0 1; do kubectl exec -it web-$i -- curl localhost; done
web-0
web-1
尽管你同时删除了 StatefulSet 和 web-0 Pod,但它仍然使用最初写入 index.html 文件的主机名进行服务。这是因为 StatefulSet 永远不会删除和一个 Pod 相关联的 PersistentVolumes。当你重建这个 StatefulSet 并且重新启动了 web-0 时,它原本的 PersistentVolume 会被重新挂载。
级联删除 在一个终端窗口观察 StatefulSet 里的 Pod。
kubectl get pods -w -l app = nginx
在另一个窗口中再次删除这个 StatefulSet。这次省略 --cascade=false 参数。
kubectl delete statefulset web
statefulset.apps "web" deleted
在第一个终端检查 kubectl get 命令的输出,并等待所有的 Pod 变成 Terminating 状态。
kubectl get pods -w -l app = nginx
NAME READY STATUS RESTARTS AGE
web-0 1/1 Running 0 11m
web-1 1/1 Running 0 27m
NAME READY STATUS RESTARTS AGE
web-0 1/1 Terminating 0 12m
web-1 1/1 Terminating 0 29m
web-0 0/1 Terminating 0 12m
web-0 0/1 Terminating 0 12m
web-0 0/1 Terminating 0 12m
web-1 0/1 Terminating 0 29m
web-1 0/1 Terminating 0 29m
web-1 0/1 Terminating 0 29m
如同你在缩容 一节看到的,Pod 按照和他们序号索引相反的顺序每次终止一个。在终止一个 Pod 前,StatefulSet 控制器会等待 Pod 后继者被完全终止。
请注意,虽然级联删除会删除 StatefulSet 和它的 Pod,但它并不会删除和 StatefulSet 关联的 Headless Service。你必须手动删除nginx Service。
kubectl delete service nginx
service "nginx" deleted
再一次重新创建 StatefulSet 和 Headless Service。
kubectl apply -f web.yaml
service/nginx created
statefulset.apps/web created
当 StatefulSet 所有的 Pod 变成 Running 和 Ready 时,获取它们的 index.html 文件的内容。
for i in 0 1; do kubectl exec -it web-$i -- curl localhost; done
web-0
web-1
即使你已经删除了 StatefulSet 和它的全部 Pod,这些 Pod 将会被重新创建并挂载它们的 PersistentVolumes,并且 web-0 和 web-1 将仍然使用它们的主机名提供服务。
最后删除 nginx service...
kubectl delete service nginx
service "nginx" deleted
... 并且删除 web StatefulSet:
kubectl delete statefulset web
statefulset "web" deleted
Pod 管理策略 对于某些分布式系统来说,StatefulSet 的顺序性保证是不必要和/或者不应该的。这些系统仅仅要求唯一性和身份标志。为了解决这个问题,在 Kubernetes 1.7 中我们针对 StatefulSet API Object 引入了 .spec.podManagementPolicy。
OrderedReady Pod 管理策略 OrderedReady pod 管理策略是 StatefulSets 的默认选项。它告诉 StatefulSet 控制器遵循上文展示的顺序性保证。
Parallel Pod 管理策略 Parallel pod 管理策略告诉 StatefulSet 控制器并行的终止所有 Pod,在启动或终止另一个 Pod 前,不必等待这些 Pod 变成 Running 和 Ready 或者完全终止状态。
apiVersion : v1
kind : Service
metadata :
name : nginx
labels :
app : nginx
spec :
ports :
- port : 80
name : web
clusterIP : None
selector :
app : nginx
---
apiVersion : apps/v1
kind : StatefulSet
metadata :
name : web
spec :
serviceName : "nginx"
podManagementPolicy : "Parallel"
replicas : 2
selector :
matchLabels :
app : nginx
template :
metadata :
labels :
app : nginx
spec :
containers :
- name : nginx
image : k8s.gcr.io/nginx-slim:0.8
ports :
- containerPort : 80
name : web
volumeMounts :
- name : www
mountPath : /usr/share/nginx/html
volumeClaimTemplates :
- metadata :
name : www
spec :
accessModes : [ "ReadWriteOnce" ]
resources :
requests :
storage : 1Gi
下载上面的例子并保存为 web-parallel.yaml。
这份清单和你在上文下载的完全一样,只是 web StatefulSet 的 .spec.podManagementPolicy 设置成了 Parallel。
在一个终端窗口查看 StatefulSet 中的 Pod。
kubectl get po -lapp= nginx -w
在另一个终端窗口创建清单中的 StatefulSet 和 Service。
kubectl apply -f web-parallel.yaml
service/nginx created
statefulset.apps/web created
查看你在第一个终端中运行的 kubectl get 命令的输出。
kubectl get po -lapp= nginx -w
NAME READY STATUS RESTARTS AGE
web-0 0/1 Pending 0 0s
web-0 0/1 Pending 0 0s
web-1 0/1 Pending 0 0s
web-1 0/1 Pending 0 0s
web-0 0/1 ContainerCreating 0 0s
web-1 0/1 ContainerCreating 0 0s
web-0 1/1 Running 0 10s
web-1 1/1 Running 0 10s
StatefulSet 控制器同时启动了 web-0 和 web-1。
保持第二个终端打开,并在另一个终端窗口中扩容 StatefulSet。
kubectl scale statefulset/web --replicas= 4
statefulset.apps/web scaled
在 kubectl get 命令运行的终端里检查它的输出。
web-3 0/1 Pending 0 0s
web-3 0/1 Pending 0 0s
web-3 0/1 Pending 0 7s
web-3 0/1 ContainerCreating 0 7s
web-2 1/1 Running 0 10s
web-3 1/1 Running 0 26s
StatefulSet 控制器启动了两个新的 Pod,而且在启动第二个之前并没有等待第一个变成 Running 和 Ready 状态。
保持这个终端打开,并在另一个终端删除 web StatefulSet。
在另一个终端里再次检查 kubectl get 命令的输出。
web-3 1/1 Terminating 0 9m
web-2 1/1 Terminating 0 9m
web-3 1/1 Terminating 0 9m
web-2 1/1 Terminating 0 9m
web-1 1/1 Terminating 0 44m
web-0 1/1 Terminating 0 44m
web-0 0/1 Terminating 0 44m
web-3 0/1 Terminating 0 9m
web-2 0/1 Terminating 0 9m
web-1 0/1 Terminating 0 44m
web-0 0/1 Terminating 0 44m
web-2 0/1 Terminating 0 9m
web-2 0/1 Terminating 0 9m
web-2 0/1 Terminating 0 9m
web-1 0/1 Terminating 0 44m
web-1 0/1 Terminating 0 44m
web-1 0/1 Terminating 0 44m
web-0 0/1 Terminating 0 44m
web-0 0/1 Terminating 0 44m
web-0 0/1 Terminating 0 44m
web-3 0/1 Terminating 0 9m
web-3 0/1 Terminating 0 9m
web-3 0/1 Terminating 0 9m
StatefulSet 控制器将并发的删除所有 Pod,在删除一个 Pod 前不会等待它的顺序后继者终止。
关闭 kubectl get 命令运行的终端并删除nginx Service。
清理现场 你需要删除本教程中用到的 PersistentVolumes 的持久化存储介质。基于你的环境、存储配置和提供方式,按照必须的步骤保证回收所有的存储。
5.5.4 - 示例:使用 Stateful Sets 部署 Cassandra 目录 下文描述了在 Kubernetes 上部署一个_云原生_ Cassandra 的过程。当我们说_云原生_时,指的是一个应用能够理解它运行在一个集群管理器内部,并且使用这个集群的管理基础设施来帮助实现这个应用。特别的,本例使用了一个自定义的 Cassandra SeedProvider 帮助 Cassandra 发现新加入集群 Cassandra 节点。
本示例也使用了Kubernetes的一些核心组件:
准备工作 本示例假设你已经安装运行了一个 Kubernetes集群(版本 >=1.2),并且还在某个路径下安装了 kubectl 命令行工具。请查看 getting started guides 获取关于你的平台的安装说明。
本示例还需要一些代码和配置文件。为了避免手动输入,你可以 git clone Kubernetes 源到你本地。
Cassandra Docker 镜像 Pod 使用来自 Google 容器仓库 的 gcr.io/google-samples/cassandra:v12 镜像。这个 docker 镜像基于 debian:jessie 并包含 OpenJDK 8。该镜像包含一个从 Apache Debian 源中安装的标准 Cassandra。你可以通过使用环境变量改变插入到 cassandra.yaml 文件中的参数值。
ENV VAR DEFAULT VALUE CASSANDRA_CLUSTER_NAME 'Test Cluster' CASSANDRA_NUM_TOKENS 32 CASSANDRA_RPC_ADDRESS 0.0.0.0
快速入门 apiVersion : v1
kind : Service
metadata :
labels :
app : cassandra
name : cassandra
spec :
clusterIP : None
ports :
- port : 9042
selector :
app : cassandra
如果你希望直接跳到我们使用的命令,以下是全部步骤:
kubectl apply -f https://k8s.io/examples/application/cassandra/cassandra-service.yaml
apiVersion : apps/v1
kind : StatefulSet
metadata :
name : cassandra
labels :
app : cassandra
spec :
serviceName : cassandra
replicas : 3
selector :
matchLabels :
app : cassandra
template :
metadata :
labels :
app : cassandra
spec :
terminationGracePeriodSeconds : 1800
containers :
- name : cassandra
image : gcr.io/google-samples/cassandra:v13
imagePullPolicy : Always
ports :
- containerPort : 7000
name : intra-node
- containerPort : 7001
name : tls-intra-node
- containerPort : 7199
name : jmx
- containerPort : 9042
name : cql
resources :
limits :
cpu : "500m"
memory : 1Gi
requests :
cpu : "500m"
memory : 1Gi
securityContext :
capabilities :
add :
- IPC_LOCK
lifecycle :
preStop :
exec :
command :
- /bin/sh
- -c
- nodetool drain
env :
- name : MAX_HEAP_SIZE
value : 512M
- name : HEAP_NEWSIZE
value : 100M
- name : CASSANDRA_SEEDS
value : "cassandra-0.cassandra.default.svc.cluster.local"
- name : CASSANDRA_CLUSTER_NAME
value : "K8Demo"
- name : CASSANDRA_DC
value : "DC1-K8Demo"
- name : CASSANDRA_RACK
value : "Rack1-K8Demo"
- name : POD_IP
valueFrom :
fieldRef :
fieldPath : status.podIP
readinessProbe :
exec :
command :
- /bin/bash
- -c
- /ready-probe.sh
initialDelaySeconds : 15
timeoutSeconds : 5
# These volume mounts are persistent. They are like inline claims,
# but not exactly because the names need to match exactly one of
# the stateful pod volumes.
volumeMounts :
- name : cassandra-data
mountPath : /cassandra_data
# These are converted to volume claims by the controller
# and mounted at the paths mentioned above.
# do not use these in production until ssd GCEPersistentDisk or other ssd pd
volumeClaimTemplates :
- metadata :
name : cassandra-data
spec :
accessModes : [ "ReadWriteOnce" ]
storageClassName : fast
resources :
requests :
storage : 1Gi
---
kind : StorageClass
apiVersion : storage.k8s.io/v1
metadata :
name : fast
provisioner : k8s.io/minikube-hostpath
parameters :
type : pd-ssd
# 创建 statefulset
kubectl apply -f https://k8s.io/examples/application/cassandra/cassandra-statefulset.yaml
# 验证 Cassandra 集群。替换一个 pod 的名称。
kubectl exec -ti cassandra-0 -- nodetool status
# 清理
grace=$(kubectl get po cassandra-0 -o=jsonpath='{.spec.terminationGracePeriodSeconds}') \
&& kubectl delete statefulset,po -l app=cassandra \
&& echo "Sleeping $grace" \
&& sleep $grace \
&& kubectl delete pvc -l app=cassandra
#
# 资源控制器示例
#
# 创建一个副本控制器来复制 cassandra 节点
kubectl create -f cassandra/cassandra-controller.yaml
# 验证 Cassandra 集群。替换一个 pod 的名称。
kubectl exec -ti cassandra-xxxxx -- nodetool status
# 扩大 Cassandra 集群
kubectl scale rc cassandra --replicas=4
# 删除副本控制器
kubectl delete rc cassandra
#
# 创建一个 DaemonSet,在每个 kubernetes 节点上放置一个 cassandra 节点
#
kubectl create -f cassandra/cassandra-daemonset.yaml --validate=false
# 资源清理
kubectl delete service -l app=cassandra
kubectl delete daemonset cassandra
步骤 1:创建 Cassandra Headless Service Kubernetes Service 描述一组执行同样任务的 Pod 。在 Kubernetes 中,一个应用的原子调度单位是一个 Pod:一个或多个_必须_调度到相同主机上的容器。
这个 Service 用于在 Kubernetes 集群内部进行 Cassandra 客户端和 Cassandra Pod 之间的 DNS 查找。
以下为这个 service 的描述:
apiVersion : v1
kind : Service
metadata :
labels :
app : cassandra
name : cassandra
spec :
clusterIP : None
ports :
- port : 9042
selector :
app : cassandra
Download cassandra-service.yaml
and cassandra-statefulset.yaml
为 StatefulSet 创建 service
kubectl apply -f https://k8s.io/examples/application/cassandra/cassandra-service.yaml
以下命令显示了 service 是否被成功创建。
$ kubectl get svc cassandra
命令的响应应该像这样:
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
cassandra None <none> 9042/TCP 45s
如果返回错误则表示 service 创建失败。
步骤 2:使用 StatefulSet 创建 Cassandra Ring环 StatefulSets(以前叫做 PetSets)特性在 Kubernetes 1.5 中升级为一个 Beta 组件。在集群环境中部署类似于 Cassandra 的有状态分布式应用是一项具有挑战性的工作。我们实现了 StatefulSet,极大的简化了这个过程。本示例使用了 StatefulSet 的多个特性,但其本身超出了本文的范围。请参考 StatefulSet 文档 。
以下是 StatefulSet 的清单文件,用于创建一个由三个 pod 组成的 Cassandra ring 环。
本示例使用了 GCE Storage Class,请根据你运行的云平台做适当的修改。
apiVersion : "apps/v1beta1"
kind : StatefulSet
metadata :
name : cassandra
spec :
serviceName : cassandra
replicas : 3
template :
metadata :
labels :
app : cassandra
spec :
containers :
- name : cassandra
image : gcr.io/google-samples/cassandra:v12
imagePullPolicy : Always
ports :
- containerPort : 7000
name : intra-node
- containerPort : 7001
name : tls-intra-node
- containerPort : 7199
name : jmx
- containerPort : 9042
name : cql
resources :
limits :
cpu : "500m"
memory : 1Gi
requests :
cpu : "500m"
memory : 1Gi
securityContext :
capabilities :
add :
- IPC_LOCK
lifecycle :
preStop :
exec :
command : ["/bin/sh" , "-c" , "PID=$(pidof java) && kill $PID && while ps -p $PID > /dev/null; do sleep 1; done" ]
env :
- name : MAX_HEAP_SIZE
value : 512M
- name : HEAP_NEWSIZE
value : 100M
- name : CASSANDRA_SEEDS
value : "cassandra-0.cassandra.default.svc.cluster.local"
- name : CASSANDRA_CLUSTER_NAME
value : "K8Demo"
- name : CASSANDRA_DC
value : "DC1-K8Demo"
- name : CASSANDRA_RACK
value : "Rack1-K8Demo"
- name : CASSANDRA_AUTO_BOOTSTRAP
value : "false"
- name : POD_IP
valueFrom :
fieldRef :
fieldPath : status.podIP
readinessProbe :
exec :
command :
- /bin/bash
- -c
- /ready-probe.sh
initialDelaySeconds : 15
timeoutSeconds : 5
# These volume mounts are persistent. They are like inline claims,
# but not exactly because the names need to match exactly one of
# the stateful pod volumes.
volumeMounts :
- name : cassandra-data
mountPath : /cassandra_data
# These are converted to volume claims by the controller
# and mounted at the paths mentioned above.
# do not use these in production until ssd GCEPersistentDisk or other ssd pd
volumeClaimTemplates :
- metadata :
name : cassandra-data
annotations :
volume.beta.kubernetes.io/storage-class : fast
spec :
accessModes : [ "ReadWriteOnce" ]
resources :
requests :
storage : 1Gi
---
kind : StorageClass
apiVersion : storage.k8s.io/v1beta1
metadata :
name : fast
provisioner : kubernetes.io/gce-pd
parameters :
type : pd-ssd
创建 Cassandra StatefulSet 如下:
kubectl apply -f https://k8s.io/examples/application/cassandra/cassandra-statefulset.yaml
步骤 3:验证和修改 Cassandra StatefulSet 这个 StatefulSet 的部署展示了 StatefulSets 提供的两个新特性:
Pod 的名称已知 Pod 以递增顺序部署 首先,运行下面的 kubectl 命令,验证 StatefulSet 已经被成功部署。
$ kubectl get statefulset cassandra
这个命令的响应应该像这样:
NAME DESIRED CURRENT AGE
cassandra 3 3 13s
接下来观察 Cassandra pod 以一个接一个的形式部署。StatefulSet 资源按照数字序号的模式部署 pod:1, 2, 3 等。如果在 pod 部署前执行下面的命令,你就能够看到这种顺序的创建过程。
$ kubectl get pods -l="app=cassandra"
NAME READY STATUS RESTARTS AGE
cassandra-0 1/1 Running 0 1m
cassandra-1 0/1 ContainerCreating 0 8s
上面的示例显示了三个 Cassandra StatefulSet pod 中的两个已经部署。一旦所有的 pod 都部署成功,相同的命令会显示一个完整的 StatefulSet。
$ kubectl get pods -l="app=cassandra"
NAME READY STATUS RESTARTS AGE
cassandra-0 1/1 Running 0 10m
cassandra-1 1/1 Running 0 9m
cassandra-2 1/1 Running 0 8m
运行 Cassandra 工具 nodetool 将显示 ring 环的状态。
$ kubectl exec cassandra-0 -- nodetool status
Datacenter: DC1-K8Demo
======================
Status=Up/Down
|/ State=Normal/Leaving/Joining/Moving
-- Address Load Tokens Owns (effective) Host ID Rack
UN 10.4.2.4 65.26 KiB 32 63.7% a9d27f81-6783-461d-8583-87de2589133e Rack1-K8Demo
UN 10.4.0.4 102.04 KiB 32 66.7% 5559a58c-8b03-47ad-bc32-c621708dc2e4 Rack1-K8Demo
UN 10.4.1.4 83.06 KiB 32 69.6% 9dce943c-581d-4c0e-9543-f519969cc805 Rack1-K8Demo
你也可以运行 cqlsh 来显示集群的 keyspaces。
$ kubectl exec cassandra-0 -- cqlsh -e 'desc keyspaces'
system_traces system_schema system_auth system system_distributed
你需要使用 kubectl edit 来增加或减小 Cassandra StatefulSet 的大小。你可以在文档 中找到更多关于 edit 命令的信息。
使用以下命令编辑 StatefulSet。
$ kubectl edit statefulset cassandra
这会在你的命令行中创建一个编辑器。你需要修改的行是 replicas。这个例子没有包含终端窗口的所有内容,下面示例中的最后一行就是你希望改变的 replicas 行。
# Please edit the object below. Lines beginning with a '#' will be ignored,
# and an empty file will abort the edit. If an error occurs while saving this file will be
# reopened with the relevant failures.
#
apiVersion: apps/v1beta1
kind: StatefulSet
metadata:
creationTimestamp: 2016-08-13T18:40:58Z
generation: 1
labels:
app: cassandra
name: cassandra
namespace: default
resourceVersion: "323"
uid: 7a219483-6185-11e6-a910-42010a8a0fc0
spec:
replicas: 3
按下面的示例修改清单文件并保存。
spec:
replicas: 4
这个 StatefulSet 现在将包含四个 pod。
$ kubectl get statefulset cassandra
这个command的响应应该像这样:
NAME DESIRED CURRENT AGE
cassandra 4 4 36m
对于 Kubernetes 1.5 发布版,beta StatefulSet 资源没有像 Deployment, ReplicaSet, Replication Controller 或者 Job 一样,包含 kubectl scale 功能,
步骤 4:删除 Cassandra StatefulSet 删除或者缩容 StatefulSet 时不会删除与之关联的 volumes。这样做是为了优先保证安全。你的数据比其它会被自动清除的 StatefulSet 关联资源更宝贵。删除 Persistent Volume Claims 可能会导致关联的 volumes 被删除,这种行为依赖 storage class 和 reclaim policy。永远不要期望能在 claim 删除后访问一个 volume。
使用如下命令删除 StatefulSet。
$ grace=$(kubectl get po cassandra-0 -o=jsonpath='{.spec.terminationGracePeriodSeconds}') \
&& kubectl delete statefulset -l app=cassandra \
&& echo "Sleeping $grace" \
&& sleep $grace \
&& kubectl delete pvc -l app=cassandra
步骤 5:使用 Replication Controller 创建 Cassandra 节点 pod Kubernetes Replication Controller 负责复制一个完全相同的 pod 集合。像 Service 一样,它具有一个 selector query,用来识别它的集合成员。和 Service 不一样的是,它还具有一个期望的副本数,并且会通过创建或删除 Pod 来保证 Pod 的数量满足它期望的状态。
和我们刚才定义的 Service 一起,Replication Controller 能够让我们轻松的构建一个复制的、可扩展的 Cassandra 集群。
让我们创建一个具有两个初始副本的 replication controller。
apiVersion : v1
kind : ReplicationController
metadata :
name : cassandra
# The labels will be applied automatically
# from the labels in the pod template, if not set
# labels:
# app: cassandra
spec :
replicas : 2
# The selector will be applied automatically
# from the labels in the pod template, if not set.
# selector:
# app: cassandra
template :
metadata :
labels :
app : cassandra
spec :
containers :
- command :
- /run.sh
resources :
limits :
cpu : 0.5
env :
- name : MAX_HEAP_SIZE
value : 512M
- name : HEAP_NEWSIZE
value : 100M
- name : CASSANDRA_SEED_PROVIDER
value : "io.k8s.cassandra.KubernetesSeedProvider"
- name : POD_NAMESPACE
valueFrom :
fieldRef :
fieldPath : metadata.namespace
- name : POD_IP
valueFrom :
fieldRef :
fieldPath : status.podIP
image : gcr.io/google-samples/cassandra:v12
name : cassandra
ports :
- containerPort : 7000
name : intra-node
- containerPort : 7001
name : tls-intra-node
- containerPort : 7199
name : jmx
- containerPort : 9042
name : cql
volumeMounts :
- mountPath : /cassandra_data
name : data
volumes :
- name : data
emptyDir : {}
下载示例
在这个描述中需要注意几件事情。
selector 属性包含了控制器的 selector query。它能够被显式指定,或者在没有设置时,像此处一样从 pod 模板中的 labels 中自动应用。
Pod 模板的标签 app:cassandra 匹配步骤1中的 Service selector。这就是 Service 如何选择 replication controller 创建的 pod 的原理。
replicas 属性指明了期望的副本数量,在本例中最开始为 2。我们很快将要扩容更多数量。
创建 Replication Controller:
$ kubectl create -f cassandra/cassandra-controller.yaml
你可以列出新建的 controller:
$ kubectl get rc -o wide
NAME DESIRED CURRENT AGE CONTAINER(S) IMAGE(S) SELECTOR
cassandra 2 2 11s cassandra gcr.io/google-samples/cassandra:v12 app=cassandra
现在,如果你列出集群中的 pod,并且使用 app=cassandra 标签过滤,你应该能够看到两个 Cassandra pod。(wide 参数使你能够看到 pod 被调度到了哪个 Kubernetes 节点上)
$ kubectl get pods -l="app=cassandra" -o wide
NAME READY STATUS RESTARTS AGE NODE
cassandra-21qyy 1/1 Running 0 1m kubernetes-minion-b286
cassandra-q6sz7 1/1 Running 0 1m kubernetes-minion-9ye5
因为这些 pod 拥有 app=cassandra 标签,它们被映射给了我们在步骤 1 中创建的 service。
你可以使用下面的 service endpoint 查询命令来检查 Pod 是否对 Service 可用。
$ kubectl get endpoints cassandra -o yaml
apiVersion: v1
kind: Endpoints
metadata:
creationTimestamp: 2015-06-21T22:34:12Z
labels:
app: cassandra
name: cassandra
namespace: default
resourceVersion: "944373"
uid: a3d6c25f-1865-11e5-a34e-42010af01bcc
subsets:
- addresses:
- ip: 10.244.3.15
targetRef:
kind: Pod
name: cassandra
namespace: default
resourceVersion: "944372"
uid: 9ef9895d-1865-11e5-a34e-42010af01bcc
ports:
- port: 9042
protocol: TCP
为了显示 SeedProvider 逻辑是按设想在运行,你可以使用 nodetool 命令来检查 Cassandra 集群的状态。为此,请使用 kubectl exec 命令,这样你就能在一个 Cassandra pod 上运行 nodetool。同样的,请替换 cassandra-xxxxx 为任意一个 pods的真实名字。
$ kubectl exec -ti cassandra-xxxxx -- nodetool status
Datacenter: datacenter1
=======================
Status=Up/Down
|/ State=Normal/Leaving/Joining/Moving
-- Address Load Tokens Owns (effective) Host ID Rack
UN 10.244.0.5 74.09 KB 256 100.0% 86feda0f-f070-4a5b-bda1-2eeb0ad08b77 rack1
UN 10.244.3.3 51.28 KB 256 100.0% dafe3154-1d67-42e1-ac1d-78e7e80dce2b rack1
步骤 6:Cassandra 集群扩容 现在,让我们把 Cassandra 集群扩展到 4 个 pod。我们通过告诉 Replication Controller 现在我们需要 4 个副本来完成。
$ kubectl scale rc cassandra --replicas= 4
你可以看到列出了新的 pod:
$ kubectl get pods -l="app=cassandra" -o wide
NAME READY STATUS RESTARTS AGE NODE
cassandra-21qyy 1/1 Running 0 6m kubernetes-minion-b286
cassandra-81m2l 1/1 Running 0 47s kubernetes-minion-b286
cassandra-8qoyp 1/1 Running 0 47s kubernetes-minion-9ye5
cassandra-q6sz7 1/1 Running 0 6m kubernetes-minion-9ye5
一会儿你就能再次检查 Cassandra 集群的状态,你可以看到新的 pod 已经被自定义的 SeedProvider 检测到:
$ kubectl exec -ti cassandra-xxxxx -- nodetool status
Datacenter: datacenter1
=======================
Status=Up/Down
|/ State=Normal/Leaving/Joining/Moving
-- Address Load Tokens Owns (effective) Host ID Rack
UN 10.244.0.6 51.67 KB 256 48.9% d07b23a5-56a1-4b0b-952d-68ab95869163 rack1
UN 10.244.1.5 84.71 KB 256 50.7% e060df1f-faa2-470c-923d-ca049b0f3f38 rack1
UN 10.244.1.6 84.71 KB 256 47.0% 83ca1580-4f3c-4ec5-9b38-75036b7a297f rack1
UN 10.244.0.5 68.2 KB 256 53.4% 72ca27e2-c72c-402a-9313-1e4b61c2f839 rack1
步骤 7:删除 Replication Controller 在你开始步骤 5 之前, __删除__你在上面创建的 replication controller 。
$ kubectl delete rc cassandra
步骤 8:使用 DaemonSet 替换 Replication Controller 在 Kubernetes中,DaemonSet 能够将 pod 一对一的分布到 Kubernetes 节点上。和 ReplicationController 相同的是它也有一个用于识别它的集合成员的 selector query。但和 ReplicationController 不同的是,它拥有一个节点 selector,用于限制基于模板的 pod 可以调度的节点。并且 pod 的复制不是基于一个设置的数量,而是为每一个节点分配一个 pod。
示范用例:当部署到云平台时,预期情况是实例是短暂的并且随时可能终止。Cassandra 被搭建成为在各个节点间复制数据以便于实现数据冗余。这样的话,即使一个实例终止了,存储在它上面的数据却没有,并且集群会通过重新复制数据到其它运行节点来作为响应。
DaemonSet 设计为在 Kubernetes 集群中的每个节点上放置一个 pod。那样就会给我们带来数据冗余度。让我们创建一个 DaemonSet 来启动我们的存储集群:
apiVersion : extensions/v1beta1
kind : DaemonSet
metadata :
labels :
name : cassandra
name : cassandra
spec :
template :
metadata :
labels :
app : cassandra
spec :
# Filter to specific nodes:
# nodeSelector:
# app: cassandra
containers :
- command :
- /run.sh
env :
- name : MAX_HEAP_SIZE
value : 512M
- name : HEAP_NEWSIZE
value : 100M
- name : CASSANDRA_SEED_PROVIDER
value : "io.k8s.cassandra.KubernetesSeedProvider"
- name : POD_NAMESPACE
valueFrom :
fieldRef :
fieldPath : metadata.namespace
- name : POD_IP
valueFrom :
fieldRef :
fieldPath : status.podIP
image : gcr.io/google-samples/cassandra:v12
name : cassandra
ports :
- containerPort : 7000
name : intra-node
- containerPort : 7001
name : tls-intra-node
- containerPort : 7199
name : jmx
- containerPort : 9042
name : cql
# If you need it, it will go away in C* 4.0.
#- containerPort: 9160
# name: thrift
resources :
requests :
cpu : 0.5
volumeMounts :
- mountPath : /cassandra_data
name : data
volumes :
- name : data
emptyDir : {}
下载示例
这个 DaemonSet 绝大部分的定义和上面的 ReplicationController 完全相同;它只是简单的给 daemonset 一个创建新的 Cassandra pod 的方法,并且以集群中所有的 Cassandra 节点为目标。
不同之处在于 nodeSelector 属性,它允许 DaemonSet 以全部节点的一个子集为目标(你可以向其他资源一样标记节点),并且没有 replicas 属性,因为它使用1对1的 node-pod 关系。
创建这个 DaemonSet:
$ kubectl create -f cassandra/cassandra-daemonset.yaml
你可能需要禁用配置文件检查,像这样:
$ kubectl create -f cassandra/cassandra-daemonset.yaml --validate=false
你可以看到 DaemonSet 已经在运行:
$ kubectl get daemonset
NAME DESIRED CURRENT NODE-SELECTOR
cassandra 3 3 <none>
现在,如果你列出集群中的 pods,并且使用 app=cassandra 标签过滤,你应该能够看到你的网络中的每一个节点上都有一个(且只有一个)新的 cassandra pod。
$ kubectl get pods -l="app=cassandra" -o wide
NAME READY STATUS RESTARTS AGE NODE
cassandra-ico4r 1/1 Running 0 4s kubernetes-minion-rpo1
cassandra-kitfh 1/1 Running 0 1s kubernetes-minion-9ye5
cassandra-tzw89 1/1 Running 0 2s kubernetes-minion-b286
为了证明这是按设想的在工作,你可以再次使用 nodetool 命令来检查集群的状态。为此,请使用 kubectl exec 命令在任何一个新建的 cassandra pod 上运行 nodetool。
$ kubectl exec -ti cassandra-xxxxx -- nodetool status
Datacenter: datacenter1
=======================
Status=Up/Down
|/ State=Normal/Leaving/Joining/Moving
-- Address Load Tokens Owns (effective) Host ID Rack
UN 10.244.0.5 74.09 KB 256 100.0% 86feda0f-f070-4a5b-bda1-2eeb0ad08b77 rack1
UN 10.244.4.2 32.45 KB 256 100.0% 0b1be71a-6ffb-4895-ac3e-b9791299c141 rack1
UN 10.244.3.3 51.28 KB 256 100.0% dafe3154-1d67-42e1-ac1d-78e7e80dce2b rack1
注意 :这个示例让你在创建 DaemonSet 前删除了 cassandra 的 Replication Controller。这是因为为了保持示例的简单,RC 和 DaemonSet 使用了相同的 app=cassandra 标签(如此它们的 pod 映射到了我们创建的 service,这样 SeedProvider 就能识别它们)。
如果我们没有预先删除 RC,这两个资源在需要运行多少 pod 上将会发生冲突。如果希望的话,我们可以使用额外的标签和 selectors 来支持同时运行它们。
步骤 9:资源清理 当你准备删除你的资源时,按以下执行:
$ kubectl delete service -l app=cassandra
$ kubectl delete daemonset cassandra
Seed Provider Source 我们使用了一个自定义的 SeedProvider 来在 Kubernetes 之上运行 Cassandra。仅当你通过 replication control 或者 daemonset 部署 Cassandra 时才需要使用自定义的 seed provider。在 Cassandra 中,SeedProvider 引导 Cassandra 使用 gossip 协议来查找其它 Cassandra 节点。Seed 地址是被视为连接端点的主机。Cassandra 实例使用 seed 列表来查找彼此并学习 ring 环拓扑。KubernetesSeedProvider 通过 Kubernetes API 发现 Cassandra seeds IP 地址,那些 Cassandra 实例在 Cassandra Service 中定义。
请查阅自定义 seed provider 的 README 文档,获取 KubernetesSeedProvider 进阶配置。对于本示例来说,你应该不需要自定义 Seed Provider 的配置。
查看本示例的 image 目录,了解如何构建容器的 docker 镜像及其内容。
你可能还注意到我们设置了一些 Cassandra 参数(MAX_HEAP_SIZE和HEAP_NEWSIZE),并且增加了关于 namespace 的信息。我们还告诉 Kubernetes 容器暴露了 CQL 和 Thrift API 端口。最后,我们告诉集群管理器我们需要 0.1 cpu(0.1 核)。
!Analytics ]()
5.6 - 集群 5.6.1 - 使用 Seccomp 限制容器的系统调用 FEATURE STATE: Kubernetes v1.19 [stable]
Seccomp 代表安全计算模式,自 2.6.12 版本以来一直是 Linux 内核的功能。
它可以用来对进程的特权进行沙盒处理,从而限制了它可以从用户空间向内核进行的调用。
Kubernetes 允许你将加载到节点上的 seccomp 配置文件自动应用于 Pod 和容器。
确定工作负载所需的特权可能很困难。在本教程中,你将了解如何将 seccomp 配置文件
加载到本地 Kubernetes 集群中,如何将它们应用到 Pod,以及如何开始制作仅向容器
进程提供必要特权的配置文件。
教程目标 了解如何在节点上加载 seccomp 配置文件 了解如何将 seccomp 配置文件应用于容器 观察由容器进程进行的系统调用的审核 观察当指定了一个不存在的配置文件时的行为 观察违反 seccomp 配置的情况 了解如何创建精确的 seccomp 配置文件 了解如何应用容器运行时默认 seccomp 配置文件 准备开始 为了完成本教程中的所有步骤,你必须安装 kind
和 kubectl 。本教程将显示同时具有 alpha(v1.19 之前的版本)
和通常可用的 seccomp 功能的示例,因此请确保为所使用的版本正确配置 了集群。
创建 Seccomp 文件 这些配置文件的内容将在以后进行探讨,但现在继续进行,并将其下载到名为 profiles/ 的目录中,以便可以将其加载到集群中。
{
"defaultAction" : "SCMP_ACT_LOG"
}
{
"defaultAction" : "SCMP_ACT_ERRNO"
}
{
"defaultAction" : "SCMP_ACT_ERRNO" ,
"architectures" : [
"SCMP_ARCH_X86_64" ,
"SCMP_ARCH_X86" ,
"SCMP_ARCH_X32"
],
"syscalls" : [
{
"names" : [
"accept4" ,
"epoll_wait" ,
"pselect6" ,
"futex" ,
"madvise" ,
"epoll_ctl" ,
"getsockname" ,
"setsockopt" ,
"vfork" ,
"mmap" ,
"read" ,
"write" ,
"close" ,
"arch_prctl" ,
"sched_getaffinity" ,
"munmap" ,
"brk" ,
"rt_sigaction" ,
"rt_sigprocmask" ,
"sigaltstack" ,
"gettid" ,
"clone" ,
"bind" ,
"socket" ,
"openat" ,
"readlinkat" ,
"exit_group" ,
"epoll_create1" ,
"listen" ,
"rt_sigreturn" ,
"sched_yield" ,
"clock_gettime" ,
"connect" ,
"dup2" ,
"epoll_pwait" ,
"execve" ,
"exit" ,
"fcntl" ,
"getpid" ,
"getuid" ,
"ioctl" ,
"mprotect" ,
"nanosleep" ,
"open" ,
"poll" ,
"recvfrom" ,
"sendto" ,
"set_tid_address" ,
"setitimer" ,
"writev"
],
"action" : "SCMP_ACT_ALLOW"
}
]
}使用 Kind 创建一个本地 Kubernetes 集群 为简单起见,可以使用 kind 创建一个已经加载 seccomp 配置文件的单节点集群。
Kind 在 Docker 中运行 Kubernetes,因此集群的每个节点实际上只是一个容器。这允许将文件挂载到每个容器的文件系统中,
就像将文件挂载到节点上一样。
apiVersion : kind.x-k8s.io/v1alpha4
kind : Cluster
nodes :
- role : control-plane
extraMounts :
- hostPath : "./profiles"
containerPath : "/var/lib/kubelet/seccomp/profiles" 下载上面的这个示例,并将其保存为 kind.yaml。然后使用这个配置创建集群。
kind create cluster --config=kind.yaml
一旦这个集群已经就绪,找到作为单节点集群运行的容器:
docker ps
你应该看到输出显示正在运行的容器名称为 kind-control-plane。
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
6a96207fed4b kindest/node:v1.18.2 "/usr/local/bin/entr…" 27 seconds ago Up 24 seconds 127.0.0.1:42223->6443/tcp kind-control-plane
如果观察该容器的文件系统,则应该看到 profiles/ 目录已成功加载到 kubelet 的默认 seccomp 路径中。
使用 docker exec 在 Pod 中运行命令:
docker exec -it 6a96207fed4b ls /var/lib/kubelet/seccomp/profiles
audit.json fine-grained.json violation.json
使用 Seccomp 配置文件创建 Pod 以进行系统调用审核 首先,将 audit.json 配置文件应用到新的 Pod 中,该配置文件将记录该进程的所有系统调用。
为你的 Kubernetes 版本下载正确的清单:
apiVersion : v1
kind : Pod
metadata :
name : audit-pod
labels :
app : audit-pod
spec :
securityContext :
seccompProfile :
type : Localhost
localhostProfile : profiles/audit.json
containers :
- name : test-container
image : hashicorp/http-echo:0.2.3
args :
- "-text=just made some syscalls!"
securityContext :
allowPrivilegeEscalation : false
apiVersion : v1
kind : Pod
metadata :
name : audit-pod
labels :
app : audit-pod
annotations :
seccomp.security.alpha.kubernetes.io/pod : localhost/profiles/audit.json
spec :
containers :
- name : test-container
image : hashicorp/http-echo:0.2.3
args :
- "-text=just made some syscalls!"
securityContext :
allowPrivilegeEscalation : false 在集群中创建 Pod:
kubectl apply -f audit-pod.yaml
这个配置文件并不限制任何系统调用,所以这个 Pod 应该会成功启动。
kubectl get pod/audit-pod
NAME READY STATUS RESTARTS AGE
audit-pod 1/1 Running 0 30s
为了能够与该容器公开的端点进行交互,请创建一个 NodePort 服务,
该服务允许从 kind 控制平面容器内部访问该端点。
kubectl expose pod/audit-pod --type NodePort --port 5678
检查这个服务在这个节点上被分配了什么端口。
kubectl get svc/audit-pod
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
audit-pod NodePort 10.111.36.142 <none> 5678:32373/TCP 72s
现在你可以使用 curl 命令从 kind 控制平面容器内部通过该服务暴露出来的端口来访问这个端点。
docker exec -it 6a96207fed4b curl localhost:32373
just made some syscalls!
你可以看到该进程正在运行,但是实际上执行了哪些系统调用?因为该 Pod 是在本地集群中运行的,
你应该可以在 /var/log/syslog 日志中看到这些。打开一个新的终端窗口,使用 tail 命令来
查看来自 http-echo 的调用输出:
tail -f /var/log/syslog | grep 'http-echo'
你应该已经可以看到 http-echo 发出的一些系统调用日志,
如果你在控制面板容器内 curl 了这个端点,你会看到更多的日志。
Jul 6 15:37:40 my-machine kernel: [369128.669452] audit: type=1326 audit(1594067860.484:14536): auid=4294967295 uid=0 gid=0 ses=4294967295 pid=29064 comm="http-echo" exe="/http-echo" sig=0 arch=c000003e syscall=51 compat=0 ip=0x46fe1f code=0x7ffc0000
Jul 6 15:37:40 my-machine kernel: [369128.669453] audit: type=1326 audit(1594067860.484:14537): auid=4294967295 uid=0 gid=0 ses=4294967295 pid=29064 comm="http-echo" exe="/http-echo" sig=0 arch=c000003e syscall=54 compat=0 ip=0x46fdba code=0x7ffc0000
Jul 6 15:37:40 my-machine kernel: [369128.669455] audit: type=1326 audit(1594067860.484:14538): auid=4294967295 uid=0 gid=0 ses=4294967295 pid=29064 comm="http-echo" exe="/http-echo" sig=0 arch=c000003e syscall=202 compat=0 ip=0x455e53 code=0x7ffc0000
Jul 6 15:37:40 my-machine kernel: [369128.669456] audit: type=1326 audit(1594067860.484:14539): auid=4294967295 uid=0 gid=0 ses=4294967295 pid=29064 comm="http-echo" exe="/http-echo" sig=0 arch=c000003e syscall=288 compat=0 ip=0x46fdba code=0x7ffc0000
Jul 6 15:37:40 my-machine kernel: [369128.669517] audit: type=1326 audit(1594067860.484:14540): auid=4294967295 uid=0 gid=0 ses=4294967295 pid=29064 comm="http-echo" exe="/http-echo" sig=0 arch=c000003e syscall=0 compat=0 ip=0x46fd44 code=0x7ffc0000
Jul 6 15:37:40 my-machine kernel: [369128.669519] audit: type=1326 audit(1594067860.484:14541): auid=4294967295 uid=0 gid=0 ses=4294967295 pid=29064 comm="http-echo" exe="/http-echo" sig=0 arch=c000003e syscall=270 compat=0 ip=0x4559b1 code=0x7ffc0000
Jul 6 15:38:40 my-machine kernel: [369188.671648] audit: type=1326 audit(1594067920.488:14559): auid=4294967295 uid=0 gid=0 ses=4294967295 pid=29064 comm="http-echo" exe="/http-echo" sig=0 arch=c000003e syscall=270 compat=0 ip=0x4559b1 code=0x7ffc0000
Jul 6 15:38:40 my-machine kernel: [369188.671726] audit: type=1326 audit(1594067920.488:14560): auid=4294967295 uid=0 gid=0 ses=4294967295 pid=29064 comm="http-echo" exe="/http-echo" sig=0 arch=c000003e syscall=202 compat=0 ip=0x455e53 code=0x7ffc0000
通过查看每一行上的 syscall= 条目,你可以开始了解 http-echo 进程所需的系统调用。
尽管这些不太可能包含它使用的所有系统调用,但它可以作为该容器的 seccomp 配置文件的基础。
开始下一节之前,请清理该 Pod 和 Service:
kubectl delete pod/audit-pod
kubectl delete svc/audit-pod
使用导致违规的 Seccomp 配置文件创建 Pod 为了进行演示,请将不允许任何系统调用的配置文件应用于 Pod。
为你的 Kubernetes 版本下载正确的清单:
apiVersion : v1
kind : Pod
metadata :
name : violation-pod
labels :
app : violation-pod
spec :
securityContext :
seccompProfile :
type : Localhost
localhostProfile : profiles/violation.json
containers :
- name : test-container
image : hashicorp/http-echo:0.2.3
args :
- "-text=just made some syscalls!"
securityContext :
allowPrivilegeEscalation : false
apiVersion : v1
kind : Pod
metadata :
name : violation-pod
labels :
app : violation-pod
annotations :
seccomp.security.alpha.kubernetes.io/pod : localhost/profiles/violation.json
spec :
containers :
- name : test-container
image : hashicorp/http-echo:0.2.3
args :
- "-text=just made some syscalls!"
securityContext :
allowPrivilegeEscalation : false 在集群中创建 Pod:
kubectl apply -f violation-pod.yaml
如果你检查 Pod 的状态,你将会看到该 Pod 启动失败。
kubectl get pod/violation-pod
NAME READY STATUS RESTARTS AGE
violation-pod 0/1 CrashLoopBackOff 1 6s
如上例所示,http-echo 进程需要大量的系统调用。通过设置 "defaultAction": "SCMP_ACT_ERRNO",
来指示 seccomp 在任何系统调用上均出错。这是非常安全的,但是会删除执行有意义的操作的能力。
你真正想要的只是给工作负载所需的特权。
开始下一节之前,请清理该 Pod 和 Service:
kubectl delete pod/violation-pod
kubectl delete svc/violation-pod
使用设置仅允许需要的系统调用的配置文件来创建 Pod 如果你看一下 fine-pod.json 文件,你会注意到在第一个示例中配置文件设置为 "defaultAction": "SCMP_ACT_LOG" 的一些系统调用。
现在,配置文件设置为 "defaultAction": "SCMP_ACT_ERRNO",但是在 "action": "SCMP_ACT_ALLOW" 块中明确允许一组系统调用。
理想情况下,容器将成功运行,并且你将不会看到任何发送到 syslog 的消息。
为你的 Kubernetes 版本下载正确的清单:
apiVersion : v1
kind : Pod
metadata :
name : fine-pod
labels :
app : fine-pod
spec :
securityContext :
seccompProfile :
type : Localhost
localhostProfile : profiles/fine-grained.json
containers :
- name : test-container
image : hashicorp/http-echo:0.2.3
args :
- "-text=just made some syscalls!"
securityContext :
allowPrivilegeEscalation : false
apiVersion : v1
kind : Pod
metadata :
name : fine-pod
labels :
app : fine-pod
annotations :
seccomp.security.alpha.kubernetes.io/pod : localhost/profiles/fine-grained.json
spec :
containers :
- name : test-container
image : hashicorp/http-echo:0.2.3
args :
- "-text=just made some syscalls!"
securityContext :
allowPrivilegeEscalation : false 在你的集群上创建Pod:
kubectl apply -f fine-pod.yaml
Pod 应该被成功启动。
kubectl get pod/fine-pod
NAME READY STATUS RESTARTS AGE
fine-pod 1/1 Running 0 30s
打开一个新的终端窗口,使用 tail 命令查看来自 http-echo 的调用的输出:
tail -f /var/log/syslog | grep 'http-echo'
使用 NodePort 服务为该 Pod 开一个端口:
kubectl expose pod/fine-pod --type NodePort --port 5678
检查服务在该节点被分配了什么端口:
kubectl get svc/fine-pod
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
fine-pod NodePort 10.111.36.142 <none> 5678:32373/TCP 72s
使用 curl 命令从 kind 控制面板容器内部请求这个端点:
docker exec -it 6a96207fed4b curl localhost:32373
just made some syscalls!
你会看到 syslog 中没有任何输出,因为这个配置文件允许了所有需要的系统调用,
并指定如果有发生列表之外的系统调用将发生错误。从安全角度来看,这是理想的情况,
但是在分析程序时需要多付出一些努力。如果有一种简单的方法无需花费太多精力就能更接近此安全性,那就太好了。
开始下一节之前,请清理该 Pod 和 Service:
kubectl delete pod/fine-pod
kubectl delete svc/fine-pod
使用容器运行时默认的 Seccomp 配置文件创建 Pod 大多数容器运行时都提供一组允许或不允许的默认系统调用。通过使用 runtime/default 注释
或将 Pod 或容器的安全上下文中的 seccomp 类型设置为 RuntimeDefault,可以轻松地在 Kubernetes 中应用默认值。
为你的 Kubernetes 版本下载正确的清单:
apiVersion : v1
kind : Pod
metadata :
name : audit-pod
labels :
app : audit-pod
spec :
securityContext :
seccompProfile :
type : RuntimeDefault
containers :
- name : test-container
image : hashicorp/http-echo:0.2.3
args :
- "-text=just made some syscalls!"
securityContext :
allowPrivilegeEscalation : false
apiVersion : v1
kind : Pod
metadata :
name : default-pod
labels :
app : default-pod
annotations :
seccomp.security.alpha.kubernetes.io/pod : runtime/default
spec :
containers :
- name : test-container
image : hashicorp/http-echo:0.2.3
args :
- "-text=just made some syscalls!"
securityContext :
allowPrivilegeEscalation : false 默认的 seccomp 配置文件应该为大多数工作负载提供足够的权限。
接下来 额外的资源:
5.6.2 - AppArmor FEATURE STATE: Kubernetes v1.4 [beta]
Apparmor 是一个 Linux 内核安全模块,它补充了标准的基于 Linux 用户和组的安全模块将程序限制为有限资源集的权限。AppArmor 可以配置为任何应用程序减少潜在的攻击面,并且提供更加深入的防御。AppArmor 是通过配置文件进行配置的,这些配置文件被调整为报名单,列出了特定程序或者容器所需要的访问权限,如 Linux 功能、网络访问、文件权限等。每个配置文件都可以在强制 模式(阻止访问不允许的资源)或投诉 模式(仅报告冲突)下运行。
教程目标 查看如何在节点上加载配置文件示例 了解如何在 Pod 上强制执行配置文件 了解如何检查配置文件是否已加载 查看违反配置文件时会发生什么情况 查看无法加载配置文件时会发生什么情况 准备开始 务必:
Kubernetes 版本至少是 v1.4 -- AppArmor 在 Kubernetes v1.4 版本中才添加了对 AppArmor 的支持。早于 v1.4 版本的 Kubernetes 组件不知道新的 AppArmor 注释,并且将会 默认忽略 提供的任何 AppArmor 设置。为了确保您的 Pods 能够得到预期的保护,必须验证节点的 Kubelet 版本: kubectl get nodes -o= jsonpath = $'{range .items[*]}{@.metadata.name}: {@.status.nodeInfo.kubeletVersion}\n{end}'
gke-test-default-pool-239f5d02-gyn2: v1.4.0
gke-test-default-pool-239f5d02-x1kf: v1.4.0
gke-test-default-pool-239f5d02-xwux: v1.4.0
AppArmor 内核模块已启用 -- 要使 Linux 内核强制执行 AppArmor 配置文件,必须安装并且启动 AppArmor 内核模块。默认情况下,有几个发行版支持该模块,如 Ubuntu 和 SUSE,还有许多发行版提供可选支持。要检查模块是否已启用,请检查
/sys/module/apparmor/parameters/enabled 文件: cat /sys/module/apparmor/parameters/enabled
Y
如果 Kubelet 包含 AppArmor 支持(>=v1.4),如果内核模块未启用,它将拒绝运行带有 AppArmor 选项的 Pod。
说明: Ubuntu 携带了许多没有合并到上游 Linux 内核中的 AppArmor 补丁,包括添加附加钩子和特性的补丁。Kubernetes 只在上游版本中测试过,不承诺支持其他特性。
Docker 作为容器运行环境 -- 目前,支持 Kubernetes 运行的容器中只有 Docker 也支持 AppArmor。随着更多的运行时添加 AppArmor 的支持,可选项将会增多。您可以使用以下命令验证节点是否正在运行 Docker:
kubectl get nodes -o= jsonpath = $'{range .items[*]}{@.metadata.name}: {@.status.nodeInfo.containerRuntimeVersion}\n{end}'
gke-test-default-pool-239f5d02-gyn2: docker://1.11.2
gke-test-default-pool-239f5d02-x1kf: docker://1.11.2
gke-test-default-pool-239f5d02-xwux: docker://1.11.2
如果 Kubelet 包含 AppArmor 支持(>=v1.4),如果运行环境不是 Docker,它将拒绝运行带有 AppArmor 选项的 Pod。
配置文件已加载 -- 通过指定每个容器都应使用 AppArmor 配置文件,AppArmor 应用于 Pod。如果指定的任何配置文件尚未加载到内核, Kubelet (>=v1.4) 将拒绝 Pod。通过检查 /sys/kernel/security/apparmor/profiles 文件,可以查看节点加载了哪些配置文件。例如:
ssh gke-test-default-pool-239f5d02-gyn2 "sudo cat /sys/kernel/security/apparmor/profiles | sort"
apparmor-test-deny-write (enforce)
apparmor-test-audit-write (enforce)
docker-default (enforce)
k8s-nginx (enforce)
有关在节点上加载配置文件的详细信息,请参见使用配置文件设置节点 。
只要 Kubelet 版本包含 AppArmor 支持(>=v1.4),如果不满足任何先决条件,Kubelet 将拒绝带有 AppArmor 选项的 Pod。您还可以通过检查节点就绪状况消息来验证节点上的 AppArmor 支持(尽管这可能会在以后的版本中删除):
kubectl get nodes -o= jsonpath = $'{range .items[*]}{@.metadata.name}: {.status.conditions[?(@.reason=="KubeletReady")].message}\n{end}'
gke-test-default-pool-239f5d02-gyn2: kubelet is posting ready status. AppArmor enabled
gke-test-default-pool-239f5d02-x1kf: kubelet is posting ready status. AppArmor enabled
gke-test-default-pool-239f5d02-xwux: kubelet is posting ready status. AppArmor enabled
保护 Pod 说明: AppArmor 目前处于测试阶段,因此选项被指定为注释。一旦 AppArmor 被授予支持通用,注释将替换为首要的字段(更多详情参见升级到 GA 的途径 )。
AppArmor 配置文件被指定为 per-container 。要指定要用其运行 Pod 容器的 AppArmor 配置文件,请向 Pod 的元数据添加注释:
container.apparmor.security.beta.kubernetes.io/<container_name> : <profile_ref>
<container_name> 的名称是容器的简称,用以描述简介,并且简称为 <profile_ref> 。<profile_ref> 可以作为其中之一:
runtime/default 应用运行时的默认配置localhost/<profile_name> 应用在名为 <profile_name> 的主机上加载的配置文件unconfined 表示不加载配置文件有关注释和配置文件名称格式的详细信息,请参阅API 参考 。
Kubernetes AppArmor 强制执行方式首先通过检查所有先决条件都已满足,然后将配置文件选择转发到容器运行时进行强制执行。如果未满足先决条件, Pod 将被拒绝,并且不会运行。
要验证是否应用了配置文件,可以查找容器创建事件中列出的 AppArmor 安全选项:
kubectl get events | grep Created
22s 22s 1 hello-apparmor Pod spec.containers{hello} Normal Created {kubelet e2e-test-stclair-node-pool-31nt} Created container with docker id 269a53b202d3; Security:[seccomp=unconfined apparmor=k8s-apparmor-example-deny-write]
您还可以通过检查容器的 proc attr,直接验证容器的根进程是否以正确的配置文件运行:
kubectl exec <pod_name> cat /proc/1/attr/current
k8s-apparmor-example-deny-write (enforce)
举例 本例假设您已经使用 AppArmor 支持设置了一个集群。
首先,我们需要将要使用的配置文件加载到节点上。我们将使用的配置文件仅拒绝所有文件写入:
#include <tunables/global>
profile k8s-apparmor-example-deny-write flags =( attach_disconnected) {
#include <abstractions/base>
file,
# Deny all file writes.
deny /** w,
}
由于我们不知道 Pod 将被安排在那里,我们需要在所有节点上加载配置文件。在本例中,我们将只使用 SSH 来安装概要文件,但是在使用配置文件设置节点 中讨论了其他方法。
NODES =(
# The SSH-accessible domain names of your nodes
gke-test-default-pool-239f5d02-gyn2.us-central1-a.my-k8s
gke-test-default-pool-239f5d02-x1kf.us-central1-a.my-k8s
gke-test-default-pool-239f5d02-xwux.us-central1-a.my-k8s)
for NODE in ${ NODES [*]} ; do ssh $NODE 'sudo apparmor_parser -q <<EOF
#include <tunables/global>
profile k8s-apparmor-example-deny-write flags=(attach_disconnected) {
#include <abstractions/base>
file,
# Deny all file writes.
deny /** w,
}
EOF'
done
接下来,我们将运行一个带有拒绝写入配置文件的简单 "Hello AppArmor" pod:
apiVersion : v1
kind : Pod
metadata :
name : hello-apparmor
annotations :
# Tell Kubernetes to apply the AppArmor profile "k8s-apparmor-example-deny-write".
# Note that this is ignored if the Kubernetes node is not running version 1.4 or greater.
container.apparmor.security.beta.kubernetes.io/hello : localhost/k8s-apparmor-example-deny-write
spec :
containers :
- name : hello
image : busybox
command : [ "sh" , "-c" , "echo 'Hello AppArmor!' && sleep 1h" ]
kubectl create -f ./hello-apparmor.yaml
如果我们查看 pod 事件,我们可以看到 pod 容器是用 AppArmor 配置文件 "k8s-apparmor-example-deny-write" 所创建的:
kubectl get events | grep hello-apparmor
14s 14s 1 hello-apparmor Pod Normal Scheduled {default-scheduler } Successfully assigned hello-apparmor to gke-test-default-pool-239f5d02-gyn2
14s 14s 1 hello-apparmor Pod spec.containers{hello} Normal Pulling {kubelet gke-test-default-pool-239f5d02-gyn2} pulling image "busybox"
13s 13s 1 hello-apparmor Pod spec.containers{hello} Normal Pulled {kubelet gke-test-default-pool-239f5d02-gyn2} Successfully pulled image "busybox"
13s 13s 1 hello-apparmor Pod spec.containers{hello} Normal Created {kubelet gke-test-default-pool-239f5d02-gyn2} Created container with docker id 06b6cd1c0989; Security:[seccomp=unconfined apparmor=k8s-apparmor-example-deny-write]
13s 13s 1 hello-apparmor Pod spec.containers{hello} Normal Started {kubelet gke-test-default-pool-239f5d02-gyn2} Started container with docker id 06b6cd1c0989
我们可以通过检查该配置文件的 proc attr 来验证容器是否实际使用该配置文件运行:
kubectl exec hello-apparmor cat /proc/1/attr/current
k8s-apparmor-example-deny-write (enforce)
最后,我们可以看到如果试图通过写入文件来违反配置文件,会发生什么情况:
kubectl exec hello-apparmor touch /tmp/test
touch: /tmp/test: Permission denied
error: error executing remote command: command terminated with non-zero exit code: Error executing in Docker Container: 1
最后,让我们看看如果我们试图指定一个尚未加载的配置文件会发生什么:
kubectl create -f /dev/stdin <<EOF
apiVersion : v1
kind : Pod
metadata :
name : hello-apparmor-2
annotations :
container.apparmor.security.beta.kubernetes.io/hello : localhost/k8s-apparmor-example-allow-write
spec :
containers :
- name : hello
image : busybox
command : [ "sh" , "-c" , "echo 'Hello AppArmor!' && sleep 1h" ]
EOF
pod/hello-apparmor-2 created
kubectl describe pod hello-apparmor-2
Name: hello-apparmor-2
Namespace: default
Node: gke-test-default-pool-239f5d02-x1kf/
Start Time: Tue, 30 Aug 2016 17:58:56 -0700
Labels: <none>
Annotations: container.apparmor.security.beta.kubernetes.io/hello=localhost/k8s-apparmor-example-allow-write
Status: Pending
Reason: AppArmor
Message: Pod Cannot enforce AppArmor: profile "k8s-apparmor-example-allow-write" is not loaded
IP:
Controllers: <none>
Containers:
hello:
Container ID:
Image: busybox
Image ID:
Port:
Command:
sh
-c
echo 'Hello AppArmor!' && sleep 1h
State: Waiting
Reason: Blocked
Ready: False
Restart Count: 0
Environment: <none>
Mounts:
/var/run/secrets/kubernetes.io/serviceaccount from default-token-dnz7v (ro)
Conditions:
Type Status
Initialized True
Ready False
PodScheduled True
Volumes:
default-token-dnz7v:
Type: Secret (a volume populated by a Secret)
SecretName: default-token-dnz7v
Optional: false
QoS Class: BestEffort
Node-Selectors: <none>
Tolerations: <none>
Events:
FirstSeen LastSeen Count From SubobjectPath Type Reason Message
--------- -------- ----- ---- ------------- -------- ------ -------
23s 23s 1 {default-scheduler } Normal Scheduled Successfully assigned hello-apparmor-2 to e2e-test-stclair-node-pool-t1f5
23s 23s 1 {kubelet e2e-test-stclair-node-pool-t1f5} Warning AppArmor Cannot enforce AppArmor: profile "k8s-apparmor-example-allow-write" is not loaded
注意 pod 呈现失败状态,并且显示一条有用的错误信息:Pod Cannot enforce AppArmor: profile "k8s-apparmor-example-allow-write" 未加载。还用相同的消息记录了一个事件。
管理 使用配置文件设置节点 Kubernetes 目前不提供任何本地机制来将 AppArmor 配置文件加载到节点上。有很多方法可以设置配置文件,例如:
通过在每个节点上运行 Pod 的DaemonSet 确保加载了正确的配置文件。可以找到一个示例实现这里 。 在节点初始化时,使用节点初始化脚本(例如 Salt 、Ansible 等)或镜像。 通过将配置文件复制到每个节点并通过 SSH 加载它们,如示例 。 调度程序不知道哪些配置文件加载到哪个节点上,因此必须将全套配置文件加载到每个节点上。另一种方法是为节点上的每个配置文件(或配置文件类)添加节点标签,并使用[节点选择器](/zh/docs/concepts/configuration/assign pod node/)确保 Pod 在具有所需配置文件的节点上运行。
使用 PodSecurityPolicy 限制配置文件 如果启用了 PodSecurityPolicy 扩展,则可以应用群集范围的 AppArmor 限制。要启用 PodSecurityPolicy,必须在“apiserver”上设置以下标志:
--enable-admission-plugins=PodSecurityPolicy[,others...]
AppArmor 选项可以指定为 PodSecurityPolicy 上的注释:
apparmor.security.beta.kubernetes.io/defaultProfileName : <profile_ref>
apparmor.security.beta.kubernetes.io/allowedProfileNames : <profile_ref>[,others...]
默认配置文件名选项指定默认情况下在未指定任何配置文件时应用于容器的配置文件。节点允许配置文件名选项指定允许 Pod 容器运行时的配置文件列表。配置文件的指定格式与容器上的相同。完整规范见API 参考 。
禁用 AppArmor 如果您不希望 AppArmor 在集群上可用,可以通过命令行标志禁用它:
--feature-gates=AppArmor=false
禁用时,任何包含 AppArmor 配置文件的 Pod 都将因 "Forbidden" 错误而导致验证失败。注意,默认情况下,docker 总是在非特权 pods 上启用 "docker-default" 配置文件(如果 AppArmor 内核模块已启用),并且即使功能门已禁用,也将继续启用该配置文件。当 AppArmor 应用于通用(GA)时,禁用 Apparmor 的选项将被删除。
使用 AppArmor 升级到 Kubernetes v1.4 不需要对 AppArmor 执行任何操作即可将集群升级到 v1.4。但是,如果任何现有的 pods 有一个 AppArmor 注释,它们将不会通过验证(或 PodSecurityPolicy 认证)。如果节点上加载了许可配置文件,恶意用户可以预先应用许可配置文件,将 pod 权限提升到 docker-default 权限之上。如果存在这个问题,建议清除包含 apparmor.security.beta.kubernetes.io 注释的任何 pods 的集群。
升级到一般可用性的途径 当 Apparmor 准备升级到通用(GA)时,当前指定的选项通过注释将转换为字段。通过转换支持所有升级和降级路径是非常微妙的,并将在转换发生时详细解释。我们将承诺在至少两个版本中同时支持字段和注释,并在之后的至少两个版本中显式拒绝注释。
编写配置文件 获得正确指定的 AppArmor 配置文件可能是一件棘手的事情。幸运的是,有一些工具可以帮助您做到这一点:
aa-genprof and aa-logprof 通过监视应用程序的活动和日志并承认它所采取的操作来生成配置文件规则。更多说明由AppArmor 文档 提供。bane 是一个用于 Docker的 AppArmor 档案生成器,它使用简化的档案语言。建议在开发工作站上通过 Docker 运行应用程序以生成配置文件,但是没有什么可以阻止在运行 Pod 的 Kubernetes 节点上运行工具。
想要调试 AppArmor 的问题,您可以检查系统日志,查看具体拒绝了什么。AppArmor 将详细消息记录到 dmesg ,错误通常可以在系统日志中或通过 journalctl 找到。更多详细信息见AppArmor 失败 。
API 参考 Pod 注释 指定容器将使用的配置文件:
key : container.apparmor.security.beta.kubernetes.io/<container_name> 中的 <container_name> 匹配 Pod 中的容器名称。
可以为 Pod 中的每个容器指定单独的配置文件。value : 配置文件参考,如下所述配置文件参考 runtime/default: 指默认运行时配置文件。等同于不指定配置文件(没有 PodSecurityPolicy 默认值),除非它仍然需要启用 AppArmor。 对于 Docker,这将解析为非特权容器的Docker default 配置文件,特权容器的配置文件为未定义(无配置文件)。 localhost/<profile_name>: 指按名称加载到节点(localhost)上的配置文件。unconfined: 这有效地禁用了容器上的 AppArmor 。任何其他配置文件引用格式无效。
PodSecurityPolicy 注解 指定在未提供容器时应用于容器的默认配置文件:
key : apparmor.security.beta.kubernetes.io/defaultProfileNamevalue : 如上述文件参考所述上面描述的指定配置文件, Pod 容器列表的配置文件引用允许指定:
key : apparmor.security.beta.kubernetes.io/allowedProfileNamesvalue : 配置文件引用的逗号分隔列表(如上所述)尽管转义逗号是配置文件名中的合法字符,但此处不能显式允许。 接下来 其他资源
5.7 - Services 5.7.1 - 使用 Source IP Kubernetes 集群中运行的应用通过 Service 抽象来互相查找、通信和与外部世界沟通。本文介绍被发送到不同类型 Services 的数据包源 IP 的变化过程,你可以根据你的需求改变这些行为。
准备开始
你必须拥有一个 Kubernetes 的集群,同时你的 Kubernetes 集群必须带有 kubectl 命令行工具。
如果你还没有集群,你可以通过 Minikube 构建一
个你自己的集群,或者你可以使用下面任意一个 Kubernetes 工具构建:
要获知版本信息,请输入
kubectl version.
术语表 本文使用了下列术语:
准备工作 你必须拥有一个正常工作的 Kubernetes 1.5 集群来运行此文档中的示例。该示例使用一个简单的 nginx webserver,通过一个HTTP消息头返回它接收到请求的源IP。你可以像下面这样创建它:
kubectl create deployment source-ip-app --image=k8s.gcr.io/echoserver:1.4
输出结果为
deployment.apps/source-ip-app created
教程目标 通过多种类型的 Services 暴露一个简单应用 理解每种 Service 类型如何处理源 IP NAT 理解保留源IP所涉及的折中 Type=ClusterIP 类型 Services 的 Source IP 如果你的 kube-proxy 运行在 iptables 模式 下,从集群内部发送到 ClusterIP 的包永远不会进行源地址 NAT,这从 Kubernetes 1.2 开始是默认选项。Kube-proxy 通过一个 proxyMode endpoint 暴露它的模式。
kubectl get nodes
输出结果与以下结果类似:
NAME STATUS ROLES AGE VERSION
kubernetes-node-6jst Ready <none> 2h v1.13.0
kubernetes-node-cx31 Ready <none> 2h v1.13.0
kubernetes-node-jj1t Ready <none> 2h v1.13.0
从其中一个节点中得到代理模式
kubernetes-node-6jst $ curl localhost:10249/proxyMode
输出结果为:
iptables
你可以通过在source IP应用上创建一个Service来测试源IP保留。
kubectl expose deployment source-ip-app --name=clusterip --port=80 --target-port=8080
输出结果为:
service/clusterip exposed
kubectl get svc clusterip
输出结果与以下结果类似:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
clusterip ClusterIP 10.0.170.92 <none> 80/TCP 51s
从相同集群中的一个 pod 访问这个 ClusterIP:
kubectl run busybox -it --image= busybox --restart= Never --rm
输出结果与以下结果类似:
Waiting for pod default/busybox to be running, status is Pending, pod ready: false
If you don't see a command prompt, try pressing enter.
然后你可以在 Pod 内运行命令:
# 在终端内使用"kubectl run"执行
ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
3: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1460 qdisc noqueue
link/ether 0a:58:0a:f4:03:08 brd ff:ff:ff:ff:ff:ff
inet 10.244.3.8/24 scope global eth0
valid_lft forever preferred_lft forever
inet6 fe80::188a:84ff:feb0:26a5/64 scope link
valid_lft forever preferred_lft forever
然后使用 wget 去请求本地 Web 服务器
# 用名为 "clusterip" 的服务的 IPv4 地址替换 "10.0.170.92"
wget -qO - 10.0.170.92
CLIENT VALUES:
client_address=10.244.3.8
command=GET
...
无论客户端 pod 和 服务端 pod 是否在相同的节点上,client_address 始终是客户端 pod 的 IP 地址。
Type=NodePort 类型 Services 的 Source IP 从 Kubernetes 1.5 开始,发送给类型为 Type=NodePort Services 的数据包默认进行源地址 NAT。你可以通过创建一个 NodePort Service 来进行测试:
kubectl expose deployment source-ip-app --name=nodeport --port=80 --target-port=8080 --type=NodePort
输出结果为:
service/nodeport exposed
NODEPORT=$(kubectl get -o jsonpath="{.spec.ports[0].nodePort}" services nodeport)
NODES=$(kubectl get nodes -o jsonpath='{ $.items[*].status.addresses[?(@.type=="InternalIP")].address }')
如果你的集群运行在一个云服务上,你可能需要为上面报告的 nodes:nodeport 开启一条防火墙规则。
现在,你可以通过上面分配的节点端口从外部访问这个 Service。
for node in $NODES; do curl -s $node:$NODEPORT | grep -i client_address; done
输出结果与以下结果类似:
client_address=10.180.1.1
client_address=10.240.0.5
client_address=10.240.0.3
请注意,这些并不是正确的客户端 IP,它们是集群的内部 IP。这是所发生的事情:
客户端发送数据包到 node2:nodePort node2 使用它自己的 IP 地址替换数据包的源 IP 地址(SNAT)node2 使用 pod IP 地址替换数据包的目的 IP 地址数据包被路由到 node 1,然后交给 endpoint Pod 的回复被路由回 node2 Pod 的回复被发送回给客户端 用图表示:
graph LR;
client(client)-->node2[节点 2];
node2-->client;
node2-. SNAT .->node1[节点 1];
node1-. SNAT .->node2;
node1-->endpoint(端点);
classDef plain fill:#ddd,stroke:#fff,stroke-width:4px,color:#000;
classDef k8s fill:#326ce5,stroke:#fff,stroke-width:4px,color:#fff;
class node1,node2,endpoint k8s;
class client plain;
[JavaScript must be enabled to view content] 为了防止这种情况发生,Kubernetes 提供了一个特性来保留客户端的源 IP 地址(点击此处查看可用特性) 。设置 service.spec.externalTrafficPolicy 的值为 Local,请求就只会被代理到本地 endpoints 而不会被转发到其它节点。这样就保留了最初的源 IP 地址。如果没有本地 endpoints,发送到这个节点的数据包将会被丢弃。这样在应用到数据包的任何包处理规则下,你都能依赖这个正确的 source-ip 使数据包通过并到达 endpoint。
设置 service.spec.externalTrafficPolicy 字段如下:
kubectl patch svc nodeport -p '{"spec":{"externalTrafficPolicy":"Local"}}'
输出结果为:
service/nodeport patched
现在,重新运行测试:
for node in $NODES; do curl --connect-timeout 1 -s $node:$NODEPORT | grep -i client_address; done
输出结果为:
client_address=104.132.1.79
请注意,你只从 endpoint pod 运行的那个节点得到了一个回复,这个回复有正确的 客户端 IP。
这是发生的事情:
客户端发送数据包到 node2:nodePort,它没有任何 endpoints 数据包被丢弃 客户端发送数据包到 node1:nodePort,它有 endpoints node1 使用正确的源 IP 地址将数据包路由到 endpoint 用图表示:
graph TD;
client --> node1[节点 1];
client(client) --x node2[节点 2];
node1 --> endpoint(端点);
endpoint --> node1;
classDef plain fill:#ddd,stroke:#fff,stroke-width:4px,color:#000;
classDef k8s fill:#326ce5,stroke:#fff,stroke-width:4px,color:#fff;
class node1,node2,endpoint k8s;
class client plain;
[JavaScript must be enabled to view content] Type=LoadBalancer 类型 Services 的 Source IP 从Kubernetes1.5开始,发送给类型为 Type=LoadBalancer Services 的数据包默认进行源地址 NAT,这是因为所有处于 Ready 状态的可调度 Kubernetes 节点对于负载均衡的流量都是符合条件的。所以如果数据包到达一个没有 endpoint 的节点,系统将把这个包代理到有 endpoint 的节点,并替换数据包的源 IP 为节点的 IP(如前面章节所述)。
你可以通过在一个 loadbalancer 上暴露这个 source-ip-app 来进行测试。
kubectl expose deployment source-ip-app --name=loadbalancer --port=80 --target-port=8080 --type=LoadBalancer
输出结果为:
service/loadbalancer exposed
打印Service的IPs:
kubectl get svc loadbalancer
输出结果与以下结果类似:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
loadbalancer LoadBalancer 10.0.65.118 104.198.149.140 80/TCP 5m
curl 104.198.149.140
输出结果与以下结果类似:
CLIENT VALUES:
client_address=10.240.0.5
...
然而,如果你的集群运行在 Google Kubernetes Engine/GCE 上,可以通过设置 service.spec.externalTrafficPolicy 字段值为 Local ,故意导致健康检查失败来强制使没有 endpoints 的节点把自己从负载均衡流量的可选节点列表中删除。
用图表示:
你可以设置 annotation 来进行测试:
kubectl patch svc loadbalancer -p '{"spec":{"externalTrafficPolicy":"Local"}}'
你应该能够立即看到 Kubernetes 分配的 service.spec.healthCheckNodePort 字段:
kubectl get svc loadbalancer -o yaml | grep -i healthCheckNodePort
输出结果与以下结果类似:
healthCheckNodePort: 32122
service.spec.healthCheckNodePort 字段指向每个节点在 /healthz 路径上提供的用于健康检查的端口。你可以这样测试:
kubectl get pod -o wide -l run=source-ip-app
输出结果与以下结果类似:
NAME READY STATUS RESTARTS AGE IP NODE
source-ip-app-826191075-qehz4 1/1 Running 0 20h 10.180.1.136 kubernetes-node-6jst
使用 curl 命令发送请求到每个节点的 /healthz 路径。
kubernetes-node-6jst $ curl localhost:32122/healthz
输出结果与以下结果类似:
1 Service Endpoints found
kubernetes-node-jj1t $ curl localhost:32122/healthz
输出结果与以下结果类似:
No Service Endpoints Found
主节点运行的 service 控制器负责分配 cloud loadbalancer。在这样做的同时,它也会分配指向每个节点的 HTTP 健康检查的 port/path。等待大约 10 秒钟之后,没有 endpoints 的两个节点的健康检查会失败,然后 curl 负载均衡器的 ip:
curl 104.198.149.140
输出结果与以下结果类似:
CLIENT VALUES:
client_address=104.132.1.79
...
跨平台支持
从 Kubernetes 1.5 开始,通过类型为 Type=LoadBalancer 的 Services 进行源 IP 保存的支持仅在一部分 cloudproviders 中实现(GCP and Azure)。你的集群运行的 cloudprovider 可能以某些不同的方式满足 loadbalancer 的要求:
使用一个代理终止客户端连接并打开一个到你的 nodes/endpoints 的新连接。在这种情况下,源 IP 地址将永远是云负载均衡器的地址而不是客户端的。
使用一个包转发器,因此从客户端发送到负载均衡器 VIP 的请求在拥有客户端源 IP 地址的节点终止,而不被中间代理。
第一类负载均衡器必须使用一种它和后端之间约定的协议来和真实的客户端 IP 通信,例如 HTTP X-FORWARDED-FOR 头,或者 proxy 协议 。
第二类负载均衡器可以通过简单的在保存于 Service 的 service.spec.healthCheckNodePort 字段上创建一个 HTTP 健康检查点来使用上面描述的特性。
清理现场 删除服务:
$ kubectl delete svc -l app=source-ip-app
删除 Deployment、ReplicaSet 和 Pod:
$ kubectl delete deployment source-ip-app
接下来 6 - 参考 这是 Kubernetes 文档的参考部分。
API 参考 API 客户端库 如果您需要通过编程语言调用 Kubernetes API,您可以使用
客户端库 。以下是官方支持的客户端库:
CLI 参考 kubectl - 主要的 CLI 工具,用于运行命令和管理 Kubernetes 集群。kubeadm - 此 CLI 工具可轻松配置安全的 Kubernetes 集群。组件参考 设计文档 Kubernetes 功能的设计文档归档,不妨考虑从
Kubernetes 架构 和
Kubernetes 设计概述
开始阅读。
6.1 - 标准化词汇表 6.2 - API 概述 本文提供了 Kubernetes API 的参考信息。
REST API 是 Kubernetes 的基本结构。
所有操作和组件之间的通信及外部用户命令都是调用 API 服务器处理的 REST API。
因此,Kubernetes 平台视一切皆为 API 对象,
且它们在 API 中有相应的定义。
Kubernetes API 参考 列
出了 Kubernetes v1.20 版本的 API。
如需了解一般背景信息,请查阅 Kubernetes API 。
Kubernetes API 控制访问 描述了客户端如何
向 Kubernetes API 服务器进行身份认证以及他们的请求如何被鉴权。
API 版本控制 JSON 和 Protobuf 序列化模式遵循相同的模式更改原则。
以下描述涵盖了这两种格式。
API 版本控制和软件版本控制是间接相关的。
API 和发布版本控制提案
描述了 API 版本控制和软件版本控制间的关系。
不同的 API 版本代表着不同的稳定性和支持级别。
你可以在 API 变更文档
中查看到更多的不同级别的判定标准。
下面是每个级别的摘要:
Alpha:版本名称包含 alpha(例如,v1alpha1)。 软件可能会有 Bug。启用某个特性可能会暴露出 Bug。
某些特性可能默认禁用。 对某个特性的支持可能会随时被删除,恕不另行通知。 API 可能在以后的软件版本中以不兼容的方式更改,恕不另行通知。 由于缺陷风险增加和缺乏长期支持,建议该软件仅用于短期测试集群。 Beta:版本名称包含 beta (例如, v2beta3)。 软件被很好的测试过。启用某个特性被认为是安全的。
特性默认开启。 尽管一些特性会发生细节上的变化,但它们将会被长期支持。 在随后的 Beta 版或稳定版中,对象的模式和(或)语义可能以不兼容的方式改变。
当这种情况发生时,将提供迁移说明。
模式更改可能需要删除、编辑和重建 API 对象。
编辑过程可能并不简单。
对于依赖此功能的应用程序,可能需要停机迁移。 该版本的软件不建议生产使用。
后续发布版本可能会有不兼容的变动。
如果你有多个集群可以独立升级,可以放宽这一限制。 说明: 请试用测试版特性时并提供反馈。特性完成 Beta 阶段测试后,
就可能不会有太多的变更了。
Stable:版本名称如 vX,其中 X 为整数。 特性的稳定版本会出现在后续很多版本的发布软件中。 API 组 API 组
能够简化对 Kubernetes API 的扩展。
API 组信息出现在REST 路径中,也出现在序列化对象的 apiVersion 字段中。
以下是 Kubernetes 中的几个组:
核心 (也叫 legacy )组的 REST 路径为 /api/v1。
核心组并不作为 apiVersion 字段的一部分,例如, apiVersion: v1。指定的组位于 REST 路径 /apis/$GROUP_NAME/$VERSION,
并且使用 apiVersion: $GROUP_NAME/$VERSION (例如, apiVersion: batch/v1)。
你可以在 Kubernetes API 参考文档
中查看全部的 API 组。 启用或禁用 API 组 资源和 API 组是在默认情况下被启用的。
你可以通过在 API 服务器上设置 --runtime-config 参数来启用或禁用它们。
--runtime-config 参数接受逗号分隔的 <key>[=<value>] 对,
来描述 API 服务器的运行时配置。如果省略了 =<value> 部分,那么视其指定为 =true。
例如:
禁用 batch/v1, 对应参数设置 --runtime-config=batch/v1=false 启用 batch/v2alpha1, 对应参数设置 --runtime-config=batch/v2alpha1 说明: 启用或禁用组或资源时,
你需要重启 API 服务器和控制器管理器来使 --runtime-config 生效。
持久化 Kubernetes 通过 API 资源来将序列化的状态写到 etcd 中存储。
接下来 6.2.1 - Kubernetes API 概念 本页描述 Kubernetes API 的通用概念。
Kubernetes API 是基于资源的(RESTful)、通过 HTTP 提供的编程接口。
API 支持通过标准的 HTTP 动词(POST、PUT、PATCH、DELETE 和 GET)
检视、创建、更新和删除主要资源,为很多允许细粒度权限控制的对象提供子资源
(如将 Pod 绑定到节点上),并且出于便利性或效率考虑,支持并提供这些资源的
不同表示形式。
Kubernetes API 还通过 "watch" 和一致性的列表支持高效的资源变更通知,
从而允许其他组件对资源的状态进行高效的缓存和同步。
标准 API 术语 大多数 Kubernetes API 资源类型都是
对象 :
它们代表的是集群中某一概念的具体实例,例如一个 Pod 或名字空间。
为数不多的几个 API 资源类型是“虚拟的” - 它们通常代表的是操作而非对象本身,
例如访问权限检查(使用 POST 请求发送一个 JSON 编码的 SubjectAccessReview
负载到 subjectaccessreviews 资源)。
所有对象都有一个唯一的名字,以便支持幂等的创建和检视操作,不过如果虚拟资源类型
不可检视或者不要求幂等,可以不具有唯一的名字。
Kubernetes 一般会利用标准的 RESTful 术语来描述 API 概念:
资源类型(Resource Type) 是在 URL 中使用的名称(pods、namespaces、services)所有资源类型都有具有一个 JSON 形式(其对象的模式定义)的具体表示,称作类别(Kind) 某资源类型的实例的列表称作 集合(Collection) 资源类型的单个实例被称作 资源(Resource) 所有资源类型要么是集群作用域的(/apis/GROUP/VERSION/*),要么是名字空间
作用域的(/apis/GROUP/VERSION/namespaces/NAMESPACE/*)。
名字空间作用域的资源类型会在其名字空间被删除时也被删除,并且对该资源类型的
访问是由定义在名字空间域中的授权检查来控制的。
下列路径用来检视集合和资源:
集群作用域的资源:GET /apis/GROUP/VERSION/RESOURCETYPE - 返回指定资源类型的资源的集合GET /apis/GROUP/VERSION/RESOURCETYPE/NAME - 返回指定资源类型下名称为 NAME 的资源 名字空间作用域的资源:GET /apis/GROUP/VERSION/RESOURCETYPE - 返回所有名字空间中指定资源类型的全部实例的集合GET /apis/GROUP/VERSION/namespaces/NAMESPACE/RESOURCETYPE - 返回名字空间 NAMESPACE 内给定资源类型的全部实例的集合GET /apis/GROUP/VERSION/namespaces/NAMESPACE/RESOURCETYPE/NAME - 返回名字空间 NAMESPACE 中给定资源类型的名称为 NAME 的实例 由于名字空间本身是一个集群作用域的资源类型,你可以通过 GET /api/v1/namespaces/
检视所有名字空间的列表,使用 GET /api/v1/namespaces/NAME 查看特定名字空间的
详细信息。
几乎所有对象资源类型都支持标准的 HTTP 动词 - GET、POST、PUT、PATCH 和 DELETE。
Kubernetes 使用术语 list 来描述返回资源集合的操作,以便与返回单个资源的、
通常称作 get 的操作相区分。
某些资源类型有一个或多个子资源(Sub-resource),表现为对应资源下面的子路径:
集群作用域的子资源:GET /apis/GROUP/VERSION/RESOURCETYPE/NAME/SUBRESOURCE 名字空间作用域的子资源:GET /apis/GROUP/VERSION/namespaces/NAMESPACE/RESOURCETYPE/NAME/SUBRESOURCE 取决于对象是什么,每个子资源所支持的动词有所不同 - 参见 API 文档以了解更多信息。
跨多个资源来访问其子资源是不可能的 - 如果需要这一能力,则通常意味着需要一种
新的虚拟资源类型了。
高效检测变更 为了使客户端能够构造一个模型来表达集群的当前状态,所有 Kubernetes 对象资源类型
都需要支持一致的列表和一个称作 watch 的增量变更通知信源(feed)。
每个 Kubernetes 对象都有一个 resourceVersion 字段,代表该资源在下层数据库中
存储的版本。检视资源集合(名字空间作用域或集群作用域)时,服务器返回的响应
中会包含 resourceVersion 值,可用来向服务器发起 watch 请求。
服务器会返回所提供的 resourceVersion 之后发生的所有变更(创建、删除和更新)。
这使得客户端能够取回当前的状态并监视其变更,且不会错过任何变更事件。
客户端的监视连接被断开时,可以从最后返回的 resourceVersion 重启新的监视连接,
或者执行一个新的集合请求之后从头开始监视操作。
参阅资源版本语义 以了解更多细节。
例如:
列举给定名字空间中的所有 Pods:
GET /api/v1/namespaces/test/pods
---
200 OK
Content-Type: application/json
{
"kind": "PodList",
"apiVersion": "v1",
"metadata": {"resourceVersion":"10245"},
"items": [...]
}
从资源版本 10245 开始,以 JSON 对象的形式接收所有创建、删除或更新操作的通知:
GET /api/v1/namespaces/test/pods?watch=1&resourceVersion=10245
---
200 OK
Transfer-Encoding: chunked
Content-Type: application/json
{
"type": "ADDED",
"object": {"kind": "Pod", "apiVersion": "v1", "metadata": {"resourceVersion": "10596", ...}, ...}
}
{
"type": "MODIFIED",
"object": {"kind": "Pod", "apiVersion": "v1", "metadata": {"resourceVersion": "11020", ...}, ...}
}
...
给定的 Kubernetes 服务器只会保留一定的时间内发生的历史变更列表。
使用 etcd3 的集群默认保存过去 5 分钟内发生的变更。
当所请求的 watch 操作因为资源的历史版本不存在而失败,客户端必须能够处理
因此而返回的状态代码 410 Gone,清空其本地的缓存,重新执行 list 操作,
并基于新的 list 操作所返回的 resourceVersion 来开始新的 watch 操作。
大多数客户端库都能够提供某种形式的、包含此逻辑的工具。
(在 Go 语言客户端库中,这一设施称作 Reflector,位于
k8s.io/client-go/cache 包中。)
监视书签 为了处理历史窗口过短的问题,我们引入了 bookmark(书签) 监视事件的概念。
该事件是一种特殊事件,用来标示客户端所请求的、指定的 resourceVersion 之前
的所有变更都以被发送。该事件中返回的对象是所请求的资源类型,但其中仅包含
resourceVersion 字段,例如:
GET /api/v1/namespaces/test/pods?watch=1&resourceVersion=10245&allowWatchBookmarks=true
---
200 OK
Transfer-Encoding: chunked
Content-Type: application/json
{
"type": "ADDED",
"object": {"kind": "Pod", "apiVersion": "v1", "metadata": {"resourceVersion": "10596", ...}, ...}
}
...
{
"type": "BOOKMARK",
"object": {"kind": "Pod", "apiVersion": "v1", "metadata": {"resourceVersion": "12746"} }
}
通过在 watch 请求中设置 allowWatchBookmarks=true 选项,可以请求 bookmark
事件,但是客户端不能假定服务器端会按某特定时间间隔返回书签事件,甚至也不能
假定服务器一定会发送 bookmark 事件。
分块检视大体量结果 FEATURE STATE: Kubernetes v1.9 [beta]
在较大规模的集群中,检视某些资源类型的集合时可能会返回较大体量的响应数据,对
服务器和客户端都会造成影响。例如,某集群可能包含数万个 Pod,每个 Pod 的 JSON
编码都有 1-2 KB 的大小。返回所有名字空间的全部 Pod 时,其结果可能体量很大
(10-20 MB)且耗用大量的服务器资源。
从 Kubernetes 1.9 开始,服务器支持将单一的大体量集合请求分解成多个小数据块
同时还保证整个请求的一致性的能力。
各个数据块可以按顺序返回,进而降低请求的尺寸,允许面向用户的客户端以增量形式
呈现返回结果,改进系统响应效果。
为了用分块的形式返回一个列表,集合请求上可以设置两个新的参数 limit 和
continue,并且所有 list 操作的返回结果列表的 metadata 字段中会包含一个
新的 continue 字段。
客户端应该将 limit 设置为希望在每个数据块中收到的结果个数上限,而服务器则
会在结果中至多返回 limit 个资源并在集合中还有更多资源的时候包含一个
continue 值。客户端在下次请求时则可以将此 continue 值传递给服务器,
告知后者要从何处开始返回结果的下一个数据块。
通过重复这一操作直到服务器端返回空的 continue 值,客户端可以受到结果的
全集。
与 watch 操作类似,continue 令牌也会在很短的时间(默认为 5 分钟)内过期,
并在无法返回更多结果时返回 410 Gone 代码。
这时,客户端需要从头开始执行上述检视操作或者忽略 limit 参数。
例如,如果集群上有 1253 个 Pods,客户端希望每次收到包含至多 500 个 Pod 的
数据块,它应按下面的步骤来请求数据块:
列举集群中所有 Pod,每次接收至多 500 个 Pods: GET /api/v1/pods?limit=500
---
200 OK
Content-Type: application/json
{
"kind": "PodList",
"apiVersion": "v1",
"metadata": {
"resourceVersion":"10245",
"continue": "ENCODED_CONTINUE_TOKEN",
...
},
"items": [...] // returns pods 1-500
}
继续前面的调用,返回下一组 500 个 Pods: GET /api/v1/pods?limit=500&continue=ENCODED_CONTINUE_TOKEN
---
200 OK
Content-Type: application/json
{
"kind": "PodList",
"apiVersion": "v1",
"metadata": {
"resourceVersion":"10245",
"continue": "ENCODED_CONTINUE_TOKEN_2",
...
},
"items": [...] // returns pods 501-1000
}
继续前面的调用,返回最后 253 个 Pods: GET /api/v1/pods?limit=500&continue=ENCODED_CONTINUE_TOKEN_2
---
200 OK
Content-Type: application/json
{
"kind": "PodList",
"apiVersion": "v1",
"metadata": {
"resourceVersion":"10245",
"continue": "", // continue token is empty because we have reached the end of the list
...
},
"items": [...] // returns pods 1001-1253
}
注意 list 操作的 resourceVersion 在每个请求中都设置的是同一个数值,
这表明服务器要向我们展示一个一致的 Pods 快照视图。
在版本 10245 之后创建、更新或删除的 Pods 都不会显示出来,除非用户发出
list 请求时不指定 continue 令牌。
这一设计使得客户端能够将较大的响应切分为较小的数据块,且能够对较大的集合
执行监视动作而不会错失任何更新事件。
以表格形式接收资源 kubectl get 命令的输出是一个包含一个或多个资源的简单表格形式。
过去,客户端需要重复 kubectl 中所实现的表格输出和描述输出逻辑,以执行
简单的对象列表操作。
这一方法在处理某些对象时,需要引入不容忽视的逻辑。
此外,API 聚合
和定制资源
所提供的资源类型都是编译时不可预知的。这意味着,客户端必须针对无法
识别的类型提供通用的实现逻辑。
为了避免上述各种潜在的局限性,客户端可以请求服务器端返回对象的表格(Table)
表现形式,从而将打印输出的特定细节委托给服务器。
Kubernetes API 实现标准的 HTTP 内容类型(Content Type)协商:为 GET 调用
传入一个值为 application/json;as=Table;g=meta.k8s.io;v=v1beta1 的 Accept
头部即可请求服务器以 Table 的内容类型返回对象。
例如,以 Table 格式列举集群中所有 Pods:
GET /api/v1/pods
Accept: application/json;as=Table;g=meta.k8s.io;v=v1beta1
---
200 OK
Content-Type: application/json
{
"kind": "Table",
"apiVersion": "meta.k8s.io/v1beta1",
...
"columnDefinitions": [
...
]
}
对于在服务器上不存在定制的 Table 定义的 API 资源类型而言,服务器会返回
一个默认的 Table 响应,其中包含资源的 name 和 creationTimestamp 字段。
GET /apis/crd.example.com/v1alpha1/namespaces/default/resources
---
200 OK
Content-Type: application/json
...
{
"kind": "Table",
"apiVersion": "meta.k8s.io/v1beta1",
...
"columnDefinitions": [
{
"name": "Name",
"type": "string",
...
},
{
"name": "Created At",
"type": "date",
...
}
]
}
kube-apiserver 从 1.10 版本开始提供 Table 响应。
因此,并非所有 API 资源类型都支持 Table 响应,尤其是使用客户端访问较老的集群时。
如果客户端需要能够处理所有资源类型,或者有可能需要与较老的集群交互,
则需要在其 Accept 头部设定多个内容类型值,以便可以回退到非表格形式的 JSON
表示。
Accept: application/json;as=Table;g=meta.k8s.io;v=v1beta1, application/json
资源的其他表示形式 默认情况下,Kubernetes 返回 JSON 序列化的的对象并设定内容类型为
application/json。这是 API 的默认序列化格式。
不过,客户端也可出于大规模环境中更佳性能的需求而请求对象的更为高效的 Protobuf
表现形式。
Kubernetes API 实现了标准的 HTTP 内容类型协商:为 GET 调用传递一个 Accept
头部来请求服务器以所指定的内容类型返回对象,同时在通过 PUT 或 POST 调用
向服务器发送 Protobuf 格式的对象时提供 Content-Type 头部。
服务器会能够支持所请求的格式时返回 Content-Type 头部,并在所提供的内容类型
不合法时返回 406 Not acceptable(无法接受) 错误。
请参阅 API 文档了解每个 API 所支持的内容类型。
例如:
以 Protobuf 格式列举集群上的所有 Pods: GET /api/v1/pods
Accept: application/vnd.kubernetes.protobuf
---
200 OK
Content-Type: application/vnd.kubernetes.protobuf
... binary encoded PodList object
通过向服务器发送 Protobuf 编码的数据创建 Pod,但请求以 JSON 形式接收响应: POST /api/v1/namespaces/test/pods
Content-Type: application/vnd.kubernetes.protobuf
Accept: application/json
... binary encoded Pod object
---
200 OK
Content-Type: application/json
{
"kind": "Pod",
"apiVersion": "v1",
...
}
并非所有 API 资源类型都支持 Protobuf,尤其是那些通过定制资源定义(CRD)或通过
API 扩展而加入的资源。如果客户端必须能够处理所有资源类型,则应在其 Accept
头部指定多种内容类型以便可以回退到 JSON 格式:
Accept: application/vnd.kubernetes.protobuf, application/json
Protobuf encoding Kubernetes 使用封套形式来对 Protobuf 响应进行编码。
封套外层由 4 个字节的特殊数字开头,便于从磁盘文件或 etcd 中辩识 Protobuf
格式的(而不是 JSON)数据。
接下来存放的是 Protobuf 编码的封套消息,其中描述下层对象的编码和类型,最后
才是对象本身。
封套格式如下:
四个字节的特殊数字前缀:
字节 0-3: "k8s\x00" [0x6b, 0x38, 0x73, 0x00]
使用下面 IDL 来编码的 Protobuf 消息:
message Unknown {
// typeMeta 应该包含 "kind" 和 "apiVersion" 的字符串值,就像
// 对应的 JSON 对象中所设置的那样
optional TypeMeta typeMeta = 1;
// raw 中将保存用 protobuf 序列化的完整对象。
// 参阅客户端库中为指定 kind 所作的 protobuf 定义
optional bytes raw = 2;
// contentEncoding 用于 raw 数据的编码格式。未设置此值意味着没有特殊编码。
optional string contentEncoding = 3;
// contentType 包含 raw 数据所采用的序列化方法。
// 未设置此值意味着 application/vnd.kubernetes.protobuf,且通常被忽略
optional string contentType = 4;
}
message TypeMeta {
// apiVersion 是 type 对应的组名/版本
optional string apiVersion = 1;
// kind 是对象模式定义的名称。此对象应该存在一个 protobuf 定义。
optional string kind = 2;
}
收到 application/vnd.kubernetes.protobuf 格式响应的客户端在响应与预期的前缀
不匹配时应该拒绝响应,因为将来的版本可能需要以某种不兼容的方式更改序列化格式,
并且这种更改是通过变更前缀完成的。
资源删除 资源删除要经过两个阶段:1) 终止(finalization),和 2)去除。
{
"kind" : "ConfigMap" ,
"apiVersion" : "v1" ,
"metadata" : {
"finalizers" : {"url.io/neat-finalization" , "other-url.io/my-finalizer" },
"deletionTimestamp" : nil ,
}
}
当客户端首先删除某资源时,其 .metadata.deletionTimestamp 会被设置为当前时间。
一旦 .metadata.deletionTimestamp 被设置,则对终结器(finalizers)执行动作
的外部控制器就可以在任何时候、以任何顺序执行其清理工作。
这里不强调顺序是因为很可能带来 .metadata.finalizers 被锁定的风险。
.metadata.finalizers 是一个共享的字段,任何具有相关权限的主体都可以对其
执行重排序的操作。如果终结器列表要按顺序处理,则很可能导致负责列表中第一个
终结器的组件要等待负责列表中排序靠后的终结器的组件的信号(可能是字段值变更、
外部系统或者其他形式),从而导致死锁行为。
在不对终结器顺序作强制要求的情况下,终结器可以自行排序,且不会因为其在列表
中的顺序而引入任何不稳定因素。
当最后一个终结器也被移除时,资源才真正从 etcd 中移除。
单个资源 API API 动词 GET、CREATE、UPDATE、PATCH、DELETE 和 PROXY 仅支持单个资源。
这些支持单一资源的动词不支持以有序或无序列表甚或事务的形式同时提交给
多个资源。
包括 kubectl 在内的客户端将解析资源的列表,并执行单一资源的 API 请求。
API 动词 LIST 和 WATCH 支持获取多个资源,而 DELETECOLLECTION 支持删除多个
资源。
试运行 FEATURE STATE: Kubernetes v1.18 [stable]
修改性质的动词(POST、PUT、PATCH 和 DELETE)可以支持 试运行(dry
run) 模式的请求。试运行模式可帮助通过典型的请求阶段(准入控制链、合法性
检查、合并冲突)来评估请求,只是最终的对象不会写入存储。请求的响应主体与
非试运行模式下的响应尽可能接近。系统会保证试运行模式的请求不会被写入到存储
中,也不会产生其他副作用。
发起试运行请求 通过设置 dryRun 查询参数可以触发试运行模式。此参数是一个字符串,以枚举值
的形式工作且可接受的值只有:
例如:
POST /api/v1/namespaces/test/pods?dryRun=All
Content-Type: application/json
Accept: application/json
响应会与非试运行模式请求的响应看起来相同,只是某些生成字段的值可能会不同。
试运行的授权 试运行和非试运行请求的鉴权是完全相同的。因此,要发起一个试运行请求,用户必须
被授权执行非试运行请求。
例如,要在 Deployment 对象上试运行 PATCH 操作,你必须具有对 Deployment 执行
PATCH 操作的访问权限,如下面的 RBAC 规则所示:
rules :
- apiGroups : ["extensions" , "apps" ]
resources : ["deployments" ]
verbs : ["patch" ]
参阅鉴权概述 以了解鉴权细节。
生成的值 对象的某些值通常是在对象被写入数据库之前生成的。很重要的一点是不要依赖试运行
请求为这些字段所设置的值,因为试运行模式下所得到的这些值与真实请求所获得的
值很可能不同。这类字段有:
name:如果设置了 generateName 字段,则 name 会获得一个唯一的随机名称creationTimestamp/deletionTimestamp:记录对象的创建/删除时间UID:唯一性标识对象,取值随机生成(非确定性)resourceVersion: 跟踪对象的持久化(存储)版本变更性准入控制器所设置的字段 对于 Service 资源:kube-apiserver 为 v1.Service 对象分配的端口和 IP 服务器端应用 FEATURE STATE: Kubernetes v1.16 [beta]
从 Kubernetes v1.18 开始,可以启用服务器端应用 功能
特性,启用该特性后,控制面会跟踪所有新创建的对象的托管字段。服务器端应用提供了一种简洁的模式来管理字段冲突,提供服务器端的 Apply 和 Update 操作,并取代了
kubectl apply 的客户端功能。有关该特性的详细描述,请参见服务器端应用 章节
资源版本 资源版本采用字符串来表达,用来标示对象的服务器端内部版本。
客户端可以使用资源版本来判定对象是否被更改,或者在读取、列举或监视资源时
用来表达数据一致性需求。
客户端必需将资源版本视为不透明的对象,将其原封不动地传递回服务器端。
例如,客户端一定不能假定资源版本是某种数值标识,也不可以对两个资源版本值
进行比较看其是否相同(也就是不可以比较两个版本值以判断其中一个比另一个
大或小)。
客户端可以在资源中看到资源版本信息,这里的资源包括从服务器返回的 Watch 事件
以及 list 操作响应:
v1.meta/ObjectMeta - 资源
的 metadata.resourceVersion 值标明该实例上次被更改时的资源版本。
v1.meta/ListMeta - 资源集合
(即 list 操作的响应)的 metadata.resourceVersion 所标明的是 list 响应被构造
时的资源版本。
resourceVersion 参数GET、LIST 和 WATCH 操作都支持 resourceVersion 参数。
参数的具体含义取决于所执行的操作和所给的 resourceVersion 值:
对于 GET 和 LIST 而言,资源版本的语义为:
GET:
resourceVersion 未设置 resourceVersion="0" resourceVersion="<非零值>" 最新版本 任何版本 不老于给定版本
LIST:
v1.19 及以上版本的 API 服务器支持 resourceVersionMatch 参数,用以确定如何对
LIST 调用应用 resourceVersion 值。
强烈建议在为 LIST 调用设置了 resourceVersion 时也设置 resourceVersionMatch。
如果 resourceVersion 未设置,则 resourceVersionMatch 是不允许设置的。
为了向后兼容,客户端必须能够容忍服务器在某些场景下忽略 resourceVersionMatch 的行为:
当设置 resourceVersionMatch=NotOlderThan 且指定了 limit 时,客户端必须能够
处理 HTTP 410 "Gone" 响应。例如,客户端可以使用更新一点的 resourceVersion
来重试,或者回退到 resourceVersion="" (即允许返回任何版本)。
当设置了 resourceVersionMatch=Exact 且未指定 limit 时,客户端必须验证
响应数据中 ListMeta 的 resourceVersion 与所请求的 resourceVersion 匹配,
并处理二者可能不匹配的情况。例如,客户端可以重试设置了 limit 的请求。
除非你对一致性有着非常强烈的需求,使用 resourceVersionMatch=NotOlderThan
同时为 resourceVersion 设定一个已知值是优选的交互方式,因为与不设置
resourceVersion 和 resourceVersionMatch 相比,这种配置可以取得更好的
集群性能和可扩缩性。后者需要提供带票选能力的读操作。
list 操作的 resourceVersionMatch 与分页参数 resourceVersionMatch 参数 分页参数 resourceVersion 未设置 resourceVersion="0" resourceVersion="<非零值>" resourceVersionMatch 未设置 limit 未设置 最新版本 任意版本 不老于指定版本 resourceVersionMatch 未设置 limit=<n>, continue 未设置 最新版本 任意版本 精确匹配 resourceVersionMatch 未设置 limit=<n>, continue=<token> 从 token 开始、精确匹配 非法请求,视为从 token 开始、精确匹配 非法请求,返回 HTTP 400 Bad Request resourceVersionMatch=Exact [1] limit 未设置 非法请求 非法请求 精确匹配 resourceVersionMatch=Exact [1] limit=<n>, continue 未设置 非法请求 非法请求 精确匹配 resourceVersionMatch=NotOlderThan [1] limit 未设置 非法请求 任意版本 不老于指定版本 resourceVersionMatch=NotOlderThan [1] limit=<n>, continue 未设置 非法请求 任意版本 不老于指定版本
脚注:
[1] 如果服务器无法正确处理 resourceVersionMatch 参数,其行为与未设置该参数相同。
GET 和 LIST 操作的语义含义如下:
最新版本: 返回资源版本为最新的数据。所返回的数据必须一致
(通过票选读操作从 etcd 中取出)。任意版本: 返回任意资源版本的数据。优选最新可用的资源版本,不过不能保证
强一致性;返回的数据可能是任何资源版本的。请求返回的数据有可能是客户端以前
看到过的很老的资源版本。尤其在某些高可用配置环境中,网络分区或者高速缓存
未被更新等状态都可能导致这种状况。不能容忍这种不一致性的客户端不应采用此
语义。不老于指定版本: 返回至少比所提供的 resourceVersion 还要新的数据。
优选最新的可用数据,不过最终提供的可能是不老于所给 resourceVersion 的任何版本。
对于发给能够正确处理 resourceVersionMatch 参数的服务器的 LIST 请求,此语义
保证 ListMeta 中的 resourceVersion 不老于请求的 resourceVersion,不过
不对列表条目之 ObjectMeta 的 resourceVersion 提供任何保证。
这是因为 ObjectMeta.resourceVersion 所跟踪的是列表条目对象上次更新的时间,
而不是对象被返回时是否是最新。
确定版本: 返回精确匹配所给资源版本的数据。如果所指定的 resourceVersion
的数据不可用,服务器会响应 HTTP 410 "Gone"。
对于发送给能够正确处理 resourceVersionMatch 参数的服务器的 LIST 请求而言,
此语义会保证 ListMeta 中的 resourceVersion 与所请求的 resourceVersion
匹配, 不过不对列表条目之 ObjectMeta 的 resourceVersion 提供任何保证。
这是因为 ObjectMeta.resourceVersion 所跟踪的是列表条目对象上次更新的时间,
而不是对象被返回时是否是最新。
Continue 令牌、精确匹配: 返回原先带分页参数的 LIST 调用中指定的资源版本的数据。
在最初的带分页参数的 LIST 调用之后,所有分页式的 LIST 调用都使用所返回的 Continue
令牌来跟踪最初提供的资源版本,
对于 WATCH 操作而言,资源版本的语义如下:
WATCH:
watch 操作的 resourceVersion 设置 resourceVersion 未设置 resourceVersion="0" resourceVersion="<非零值>" 读取状态并从最新版本开始 读取状态并从任意版本开始 从指定版本开始
WATCH 操作语义的含义如下:
读取状态并从最新版本开始: 从最新的资源版本开始 WATCH 操作。这里的
最新版本必须是一致的(即通过票选读操作从 etcd 中取出)。为了建立初始状态,
WATCH 首先会处理一组合成的 "Added" 事件,这些事件涵盖在初始资源版本中存在
的所有资源实例。
所有后续的 WATCH 事件都是关于 WATCH 开始时所处资源版本之后发生的变更。读取状态并从任意版本开始: 警告:通过这种方式初始化的 WATCH 操作可能会
返回任何状态的停滞数据。请在使用此语义之前执行复核,并在可能的情况下采用其他
语义。此语义会从任意资源版本开始执行 WATCH 操作,优选最新的可用的资源版本,
不过不是必须的;采用任何资源版本作为起始版本都是被允许的。
WATCH 操作有可能起始于客户端已经观测到的很老的版本。在高可用配置环境中,因为
网络分裂或者高速缓存未及时更新的原因都会造成此现象。
如果客户端不能容忍这种不一致性,就不要使用此语义来启动 WATCH 操作。
为了建立初始状态,WATCH 首先会处理一组合成的 "Added" 事件,这些事件涵盖在
初始资源版本中存在的所有资源实例。
所有后续的 WATCH 事件都是关于 WATCH 开始时所处资源版本之后发生的变更。从指定版本开始: 从某确切资源版本开始执行 WATCH 操作。WATCH 事件都是
关于 WATCH 开始时所处资源版本之后发生的变更。与前面两种语义不同,WATCH 操作
开始的时候不会生成或处理为所提供资源版本合成的 "Added" 事件。
我们假定客户端既然能够提供确切资源版本,就应该已经拥有了起始资源版本对应的初始状态。"410 Gone" 响应 服务器不需要提供所有老的资源版本,在客户端请求的是早于服务器端所保留版本的
resourceVersion 时,可以返回 HTTP 410 (Gone) 状态码。
客户端必须能够容忍 410 (Gone) 响应。
参阅高效检测变更 以了解如何在监测资源时
处理 410 (Gone) 响应。
如果所请求的 resourceVersion 超出了可应用的 limit,那么取决于请求是否
是通过高速缓存来满足的,API 服务器可能会返回一个 410 Gone HTTP 响应。
不可用的资源版本 服务器不必未无法识别的资源版本提供服务。针对无法识别的资源版本的 LIST 和 GET 请求
可能会短暂等待,以期资源版本可用。如果所给的资源版本在一定的时间段内仍未变得
可用,服务器应该超时并返回 504 (Gateway Timeout),且可在响应中添加
Retry-After 响应头部字段,标明客户端在再次尝试之前应该等待多少秒钟。
目前,kube-apiserver 也能使用 Too large resource version(资源版本过高)
消息来标识这类响应。针对某无法识别的资源版本的 WATCH 操作可能会无限期
(直到请求超时)地等待下去,直到资源版本可用。
6.2.2 - 服务器端应用(Server-Side Apply) FEATURE STATE: Kubernetes v1.16 [beta]
简介 服务器端应用协助用户、控制器通过声明式配置的方式管理他们的资源。
它发送完整描述的目标(A fully specified intent),
声明式地创建和/或修改
对象 。
一个完整描述的目标并不是一个完整的对象,仅包括能体现用户意图的字段和值。
该目标(intent)可以用来创建一个新对象,
也可以通过服务器来实现与现有对象的合并 。
系统支持多个应用者(appliers)在同一个对象上开展协作。
“字段管理(field management) ”机制追踪对象字段的变化。
当一个字段值改变时,其所有权从当前管理器(manager)转移到施加变更的管理器。
当尝试将新配置应用到一个对象时,如果字段有不同的值,且由其他管理器管理,
将会引发冲突 。
冲突引发警告信号:此操作可能抹掉其他协作者的修改。
冲突可以被刻意忽略,这种情况下,值将会被改写,所有权也会发生转移。
当你从配置文件中删除一个字段,然后应用这个配置文件,
这将触发服务端应用检查此字段是否还被其他字段管理器拥有。
如果没有,那就从活动对象中删除该字段;如果有,那就重置为默认值。
该规则同样适用于 list 或 map 项目。
服务器端应用既是原有 kubectl apply 的替代品,
也是控制器发布自身变化的一个简化机制。
如果你启用了服务器端应用,控制平面就会跟踪被所有新创建对象管理的字段。
字段管理 相对于通过 kubectl 管理的注解 last-applied,
服务器端应用使用了一种更具声明式特点的方法:
它持续的跟踪用户的字段管理,而不仅仅是最后一次的执行状态。
这就意味着,作为服务器端应用的一个副作用,
关于用哪一个字段管理器负责管理对象中的哪个字段的这类信息,都要对外界开放了。
用户管理字段这件事,在服务器端应用的场景中,意味着用户依赖并期望字段的值不要改变。
最后一次对字段值做出断言的用户将被记录到当前字段管理器。
这可以通过发送 POST、 PUT、
或非应用(non-apply)方式的 PATCH 等命令来修改字段值的方式实现,
或通过把字段放在配置文件中,然后发送到服务器端应用的服务端点的方式实现。
当使用服务器端应用,尝试着去改变一个被其他人管理的字段,
会导致请求被拒绝(在没有设置强制执行时,参见冲突 )。
如果两个或以上的应用者均把同一个字段设置为相同值,他们将共享此字段的所有权。
后续任何改变共享字段值的尝试,不管由那个应用者发起,都会导致冲突。
共享字段的所有者可以放弃字段的所有权,这只需从配置文件中删除该字段即可。
字段管理的信息存储在 managedFields 字段中,该字段是对象的
metadata 中的一部分。
服务器端应用创建对象的简单示例如下:
apiVersion : v1
kind : ConfigMap
metadata :
name : test-cm
namespace : default
labels :
test-label : test
managedFields :
- manager : kubectl
operation : Apply
apiVersion : v1
time : "2010-10-10T0:00:00Z"
fieldsType : FieldsV1
fieldsV1 :
f:metadata :
f:labels :
f:test-label : {}
f:data :
f:key : {}
data :
key : some value
上述对象在 metadata.managedFields 中包含了唯一的管理器。
管理器由管理实体自身的基本信息组成,比如操作类型、API 版本、以及它管理的字段。
说明: 该字段由 API 服务器管理,用户不应该改动它。
不过,执行 Update 操作修改 metadata.managedFields 也是可实现的。
强烈不鼓励这么做,但当发生如下情况时,
比如 managedFields 进入不一致的状态(显然不应该发生这种情况),
这么做也是一个合理的尝试。
managedFields 的格式在
API
文档中描述。
冲突 冲突是一种特定的错误状态,
发生在执行 Apply 改变一个字段,而恰巧该字段被其他用户声明过主权时。
这可以防止一个应用者不小心覆盖掉其他用户设置的值。
冲突发生时,应用者有三种办法来解决它:
覆盖前值,成为唯一的管理器: 如果打算覆盖该值(或应用者是一个自动化部件,比如控制器),
应用者应该设置查询参数 force 为 true,然后再发送一次请求。
这将强制操作成功,改变字段的值,从所有其他管理器的 managedFields 条目中删除指定字段。
不覆盖前值,放弃管理权: 如果应用者不再关注该字段的值,
可以从配置文件中删掉它,再重新发送请求。
这就保持了原值不变,并从 managedFields 的应用者条目中删除该字段。
不覆盖前值,成为共享的管理器: 如果应用者仍然关注字段值,并不想覆盖它,
他们可以在配置文件中把字段的值改为和服务器对象一样,再重新发送请求。
这样在不改变字段值的前提下,
就实现了字段管理被应用者和所有声明了管理权的其他的字段管理器共享。
管理器 管理器识别出正在修改对象的工作流程(在冲突时尤其有用),
管理器可以通过修改请求的参数 fieldManager 指定。
虽然 kubectl 默认发往 kubectl 服务端点,但它则请求到应用的服务端点(apply endpoint)。
对于其他的更新,它默认的是从用户代理计算得来。
应用和更新 此特性涉及两类操作,分别是 Apply
(内容类型为 application/apply-patch+yaml 的 PATCH 请求)
和 Update (所有修改对象的其他操作)。
这两类操作都会更新字段 managedFields,但行为表现有一点不同。
说明: 不管你提交的是 JSON 数据还是 YAML 数据,
都要使用 application/apply-patch+yaml 作为 Content-Type 的值。
所有的 JSON 文档 都是合法的 YAML。
例如,在冲突发生的时候,只有 apply 操作失败,而 update 则不会。
此外,apply 操作必须通过提供一个 fieldManager 查询参数来标识自身,
而此查询参数对于 update 操作则是可选的。
最后,当使用 apply 命令时,你不能在应用中的对象中持有 managedFields。
一个包含多个管理器的对象,示例如下:
apiVersion : v1
kind : ConfigMap
metadata :
name : test-cm
namespace : default
labels :
test-label : test
managedFields :
- manager : kubectl
operation : Apply
apiVersion : v1
fields :
f:metadata :
f:labels :
f:test-label : {}
- manager : kube-controller-manager
operation : Update
apiVersion : v1
time : '2019-03-30T16:00:00.000Z'
fields :
f:data :
f:key : {}
data :
key : new value
在这个例子中,
第二个操作被管理器 kube-controller-manager 以 Update 的方式运行。
此 update 更改 data 字段的值,
并使得字段管理器被改为 kube-controller-manager。
如果把 update 操作改为 Apply,那就会因为所有权冲突的原因,导致操作失败。
合并策略 由服务器端应用实现的合并策略,提供了一个总体更稳定的对象生命周期。
服务器端应用试图依据谁管理它们来合并字段,而不只是根据值来否决。
这么做是为了多个参与者可以更简单、更稳定的更新同一个对象,且避免引起意外干扰。
当用户发送一个“完整描述的目标”对象到服务器端应用的服务端点,
服务器会将它和活动对象做一次合并,如果两者中有重复定义的值,那就以配置文件的为准。
如果配置文件中的项目集合不是此用户上一次操作项目的超集,
所有缺少的、没有其他应用者管理的项目会被删除。
关于合并时用来做决策的对象规格的更多信息,参见
sigs.k8s.io/structured-merge-diff .
Kubernetes 1.16 和 1.17 中添加了一些标记,
允许 API 开发人员描述由 list、map、和 structs 支持的合并策略。
这些标记可应用到相应类型的对象,在 Go 文件或在
CRD
的 OpenAPI 的模式中定义:
Golang 标记 OpenAPI extension 可接受的值 描述 引入版本 //+listTypex-kubernetes-list-typeatomic/set/map适用于 list。 atomic 和 set 适用于只包含标量元素的 list。 map 适用于只包含嵌套类型的 list。 如果配置为 atomic, 合并时整个列表会被替换掉; 任何时候,唯一的管理器都把列表作为一个整体来管理。如果是 set 或 map ,不同的管理器也可以分开管理条目。 1.16 //+listMapKeyx-kubernetes-list-map-keys用来唯一标识条目的 map keys 切片,例如 ["port", "protocol"] 仅当 +listType=map 时适用。组合值的字符串切片必须唯一标识列表中的条目。尽管有多个 key,listMapKey 是单数的,这是因为 key 需要在 Go 类型中单独的指定。 1.16 //+mapTypex-kubernetes-map-typeatomic/granular适用于 map。 atomic 指 map 只能被单个的管理器整个的替换。 granular 指 map 支持多个管理器各自更新自己的字段。 1.17 //+structTypex-kubernetes-map-typeatomic/granular适用于 structs;否则就像 //+mapType 有相同的用法和 openapi 注释. 1.17
自定义资源 默认情况下,服务器端应用把自定义资源看做非结构化数据。
所有的键值(keys)就像 struct 的字段一样被处理,
所有的 list 被认为是原子性的。
如果自定义资源定义(Custom Resource Definition,CRD)定义了一个
模式 ,
它包含类似以前“合并策略”章节中定义过的注解,
这些注解将在合并此类型的对象时使用。
在控制器中使用服务器端应用 控制器的开发人员可以把服务器端应用作为简化控制器的更新逻辑的方式。
读-改-写 和/或 patch 的主要区别如下所示:
应用的对象必须包含控制器关注的所有字段。 对于在控制器没有执行过应用操作之前就已经存在的字段,不能删除。
(控制器在这种用例环境下,依然可以发送一个 PATCH/UPDATE) 对象不必事先读取,resourceVersion 不必指定。 强烈推荐:设置控制器在冲突时强制执行,这是因为冲突发生时,它们没有其他解决方案或措施。
转移所有权 除了通过冲突解决方案 提供的并发控制,
服务器端应用提供了一些协作方式来将字段所有权从用户转移到控制器。
最好通过例子来说明这一点。
让我们来看看,在使用 HorizontalPodAutoscaler 资源和与之配套的控制器,
且开启了 Deployment 的自动水平扩展功能之后,
怎么安全的将 replicas 字段的所有权从用户转移到控制器。
假设用户定义了 Deployment,且 replicas 字段已经设置为期望的值:
apiVersion : apps/v1
kind : Deployment
metadata :
name : nginx-deployment
labels :
app : nginx
spec :
replicas : 3
selector :
matchLabels :
app : nginx
template :
metadata :
labels :
app : nginx
spec :
containers :
- name : nginx
image : nginx:1.14.2
并且,用户使用服务器端应用,像这样创建 Deployment:
kubectl apply -f https://k8s.io/examples/application/ssa/nginx-deployment.yaml --server-side
然后,为 Deployment 启用 HPA,例如:
kubectl autoscale deployment nginx-deployment --cpu-percent= 50 --min= 1 --max= 10
现在,用户希望从他们的配置中删除 replicas,所以他们总是和 HPA 控制器冲突。
然而,这里存在一个竟态:
在 HPA 需要调整 replicas 之前会有一个时间窗口,
如果在 HPA 写入字段成为所有者之前,用户删除了replicas,
那 API 服务器就会把 replicas 的值设为1, 也就是默认值。
这不是用户希望发生的事情,即使是暂时的。
这里有两个解决方案:
(容易) 把 replicas 留在配置文件中;当 HPA 最终写入那个字段,
系统基于此事件告诉用户:冲突发生了。在这个时间点,可以安全的删除配置文件。 (高级)然而,如果用户不想等待,比如他们想为合作伙伴保持集群清晰,
那他们就可以执行以下步骤,安全的从配置文件中删除 replicas。 首先,用户新定义一个只包含 replicas 字段的配置文件:
apiVersion : apps/v1
kind : Deployment
metadata :
name : nginx-deployment
spec :
replicas : 3
用户使用名为 handover-to-hpa 的字段管理器,应用此配置文件。
kubectl apply -f https://k8s.io/examples/application/ssa/nginx-deployment-replicas-only.yaml \
--server-side --field-manager= handover-to-hpa \
--validate= false
如果应用操作和 HPA 控制器产生冲突,那什么都不做。
冲突只是表明控制器在更早的流程中已经对字段声明过所有权。
在此时间点,用户可以从配置文件中删除 replicas 。
apiVersion : apps/v1
kind : Deployment
metadata :
name : nginx-deployment
labels :
app : nginx
spec :
selector :
matchLabels :
app : nginx
template :
metadata :
labels :
app : nginx
spec :
containers :
- name : nginx
image : nginx:1.14.2
注意,只要 HPA 控制器为 replicas 设置了一个新值,
该临时字段管理器将不再拥有任何字段,会被自动删除。
这里不需要执行清理工作。
在用户之间转移所有权 通过在配置文件中把一个字段设置为相同的值,用户可以在他们之间转移字段的所有权,
从而共享了字段的所有权。
当用户共享了字段的所有权,任何一个用户可以从他的配置文件中删除该字段,
并应用该变更,从而放弃所有权,并实现了所有权向其他用户的转移。
与客户端应用的对比 由服务器端应用实现的冲突检测和解决方案的一个结果就是,
应用者总是可以在本地状态中得到最新的字段值。
如果得不到最新值,下次执行应用操作时就会发生冲突。
解决冲突三个选项的任意一个都会保证:此应用过的配置文件是服务器上对象字段的最新子集。
这和客户端应用(Client Side Apply) 不同,如果有其他用户覆盖了此值,
过期的值被留在了应用者本地的配置文件中。
除非用户更新了特定字段,此字段才会准确,
应用者没有途径去了解下一次应用操作是否会覆盖其他用户的修改。
另一个区别是使用客户端应用的应用者不能改变他们正在使用的 API 版本,但服务器端应用支持这个场景。
从客户端应用升级到服务器端应用 客户端应用方式时,用户使用 kubectl apply 管理资源,
可以通过使用下面标记切换为使用服务器端应用。
kubectl apply --server-side [ --dry-run= server]
默认情况下,对象的字段管理从客户端应用方式迁移到 kubectl 触发的服务器端应用时,不会发生冲突。
注意: 保持注解 last-applied-configuration 是最新的。
从注解能推断出字段是由客户端应用管理的。
任何没有被客户端应用管理的字段将引发冲突。
举例说明,比如你在客户端应用之后,
使用 kubectl scale 去更新 replicas 字段,
可是该字段并没有被客户端应用所拥有,
在执行 kubectl apply --server-side 时就会产生冲突。
此操作以 kubectl 作为字段管理器来应用到服务器端应用。
作为例外,可以指定一个不同的、非默认字段管理器停止的这种行为,如下面的例子所示。
对于 kubectl 触发的服务器端应用,默认的字段管理器是 kubectl。
kubectl apply --server-side --field-manager= my-manager [ --dry-run= server]
从服务器端应用降级到客户端应用 如果你用 kubectl apply --server-side 管理一个资源,
可以直接用 kubectl apply 命令将其降级为客户端应用。
降级之所以可行,这是因为 kubectl server-side apply
会保存最新的 last-applied-configuration 注解。
此操作以 kubectl 作为字段管理器应用到服务器端应用。
作为例外,可以指定一个不同的、非默认字段管理器停止这种行为,如下面的例子所示。
对于 kubectl 触发的服务器端应用,默认的字段管理器是 kubectl。
kubectl apply --server-side --field-manager= my-manager [ --dry-run= server]
API 端点 启用了服务器端应用特性之后,
PATCH 服务端点接受额外的内容类型 application/apply-patch+yaml。
服务器端应用的用户就可以把 YAMl 格式的
部分定义对象(partially specified objects)发送到此端点。
当一个配置文件被应用时,它应该包含所有体现你意图的字段。
清除 ManagedFields 可以从对象中剥离所有 managedField,
实现方法是通过使用 MergePatch、 StrategicMergePatch、
JSONPatch、 Update、以及所有的非应用方式的操作来覆盖它。
这可以通过用空条目覆盖 managedFields 字段的方式实现。
PATCH /api/v1/namespaces/default/configmaps/example-cm
Content-Type: application/merge-patch+json
Accept: application/json
Data: {"metadata":{"managedFields": [{}]}}
PATCH /api/v1/namespaces/default/configmaps/example-cm
Content-Type: application/json-patch+json
Accept: application/json
Data: [{"op": "replace", "path": "/metadata/managedFields", "value": [{}]}]
这一操作将用只包含一个空条目的 list 覆写 managedFields,
来实现从对象中整个的去除 managedFields。
注意,只把 managedFields 设置为空 list 并不会重置字段。
这么做是有目的的,所以 managedFields 将永远不会被与该字段无关的客户删除。
在重置操作结合 managedFields 以外其他字段更改的场景中,
将导致 managedFields 首先被重置,其他改变被押后处理。
其结果是,应用者取得了同一个请求中所有字段的所有权。
注意: 对于不接受资源对象类型的子资源(sub-resources),
服务器端应用不能正确地跟踪其所有权。
如果你对这样的子资源使用服务器端应用,变更的字段将不会被跟踪。
禁用此功能 服务器端应用是一个 beta 版特性,默认启用。
要关闭此特性门控 ,
你需要在启动 kube-apiserver 时包含参数 --feature-gates ServerSideApply=false。
如果你有多个 kube-apiserver 副本,他们都应该有相同的标记设置。
6.2.3 - 客户端库 本页面包含基于各种编程语言使用 Kubernetes API 的客户端库概述。
在使用 Kubernetes REST API 编写应用程序时,
您并不需要自己实现 API 调用和 “请求/响应” 类型。
您可以根据自己的编程语言需要选择使用合适的客户端库。
客户端库通常为您处理诸如身份验证之类的常见任务。
如果 API 客户端在 Kubernetes 集群中运行,大多数客户端库可以发现并使用 Kubernetes 服务帐户进行身份验证,
或者能够理解 kubeconfig 文件
格式来读取凭据和 API 服务器地址。
官方支持的 Kubernetes 客户端库 以下客户端库由 Kubernetes SIG API Machinery 正式维护。
社区维护的客户端库 注意:
本部分链接到提供 Kubernetes 所需功能的第三方项目。Kubernetes 项目作者不负责这些项目。此页面遵循CNCF 网站指南 ,按字母顺序列出项目。要将项目添加到此列表中,请在提交更改之前阅读内容指南 。以下 Kubernetes API 客户端库是由社区,而非 Kubernetes 团队支持、维护的。
6.2.4 - Kubernetes 弃用策略 本文档详细解释系统中各个层面的弃用策略(Deprecation Policy)。
Kubernetes 是一个组件众多、贡献者人数众多的大系统。
就像很多类似的软件,所提供的功能特性集合会随着时间推移而自然发生变化,
而且有时候某个功能特性可能需要被去除。被去除的可能是一个 API、一个参数标志或者
甚至某整个功能特性。为了避免影响到现有用户,Kubernetes 对于其中渐次移除
的各个方面规定了一种弃用策略并遵从此策略。
弃用 API 的一部分 由于 Kubernetes 是一个 API 驱动的系统,API 会随着时间推移而演化,以反映
人们对问题共建的认识的变化。Kubernetes API 实际上是一个 API 集合,其中每个
成员称作“API 组(API Group)”,并且每个 API 组都是独立管理版本的。
API 版本 会有
三类,每类有不同的废弃策略:
示例 分类 v1 正式发布(Generally available,GA,稳定版本) v1beta1 Beta (预发布) v1alpha1 Alpha (试验性)
给定的 Kubernetes 发布版本中可以支持任意数量的 API 组,且每组可以包含
任意个数的版本。
下面的规则负责指导 API 元素的弃用,具体元素包括:
REST 资源(也即 API 对象) REST 资源的字段 REST 资源的注解,包含“beta”类注解但不包含“alpha”类注解 枚举值或者常数值 组件配置结构 以下是跨正式发布版本时要实施的规则,不适用于对 master 或发布分支上
不同提交之间的变化。
规则 #1:只能在增加 API 组版本号时删除 API 元素。
一旦在某个特定 API 组版本中添加了 API 元素,则该元素不可从该版本中删除,
且其行为也不能大幅度地变化,无论属于哪一类(GA、Alpha 或 Beta)。
说明: 由于历史原因,Kubernetes 中存在两个“单体式(Monolithic)”API 组 -
“core”(无组名)和“extensions”。这两个遗留 API 组中的资源会被逐渐迁移到
更为特定领域的 API 组中。
规则 #2:在给定的发布版本中,API 对象必须能够在不同的 API 版本之间来回
转换且不造成信息丢失,除非整个 REST 资源在某些版本中完全不存在。
例如,一个对象可被用 v1 来写入之后用 v2 来读出并转换为 v1,所得到的 v1 必须
与原来的 v1 对象完全相同。v2 中的表现形式可能与 v1 不同,但系统知道如何
在两个版本之间执行双向转换。
此外,v2 中添加的所有新字段都必须能够转换为 v1 再转换回来。这意味着 v1 必须
添加一个新的等效字段或者将其表现为一个注解。
规则 #3:给定类别的 API 版本在新的、稳定性未降低的 API 版本发布之前不可被废弃。
一个正式发布的(GA)API 版本可替换现有的正式 API 版本或 alpha、beta API 版本。
Beta API 版本 不可以 替代正式的 API 版本。
规则 #4a:除了每类 API 版本中的最新版本,旧的 API 版本在其被宣布被废弃之后
至少以下时长内仍需被支持:
GA:12 个月或者 3 个发布版本(取其较长者) Beta: 9 个月或者 3 个发布版本(取其较长者) Alpha: 0 个发布版本 这里也包含了关于最大支持 2 个发布版本的版本偏差 的约定。
说明: 在
#52185 被解决之前,
已经被保存到持久性存储中的 API 版本都不可以被去除。
你可以禁止这些版本所对应的 REST 末端(在符合本文中弃用时间线的前提下),
但是 API 服务器必须仍能解析和转换存储中以前写入的数据。
规则 #4b:标记为“preferred(优选的)” API 版本和给定 API 组的
“storage version(存储版本)”在既支持老版本也支持新版本的 Kubernetes 发布
版本出来以前不可以提升其版本号。
用户必须能够升级到 Kubernetes 新的发行版本,之后再回滚到前一个发行版本,且
整个过程中无需针对新的 API 版本做任何转换,也不允许出现功能损坏的情况,
除非用户显式地使用了仅在较新版本中才存在的功能特性。
就对象的存储表示而言,这一点尤其是不言自明的。
以上所有规则最好通过例子来说明。假定现有 Kubernetes 发行版本为 X,其中引入了
新的 API 组。大约每隔 3 个月会有一个新的 Kubernetes 版本被发布(每年 4 个版本)。
下面的表格描述了在一系列后续的发布版本中哪些 API 版本是受支持的。
发布版本 API 版本 优选/存储版本 注释 X v1alpha1 v1alpha1 X+1 v1alpha2 v1alpha2 v1alpha1 被去除,发布说明中会包含 "action required(采取行动)" 说明 X+2 v1beta1 v1beta1 v1alpha2 被去除,发布说明中包含对应的 "action required(采取行动)" 说明 X+3 v1beta2、v1beta1(已弃用) v1beta1 v1beta1 被弃用,发布说明中包含对应的 "action required(采取行动)" 说明 X+4 v1beta2、v1beta1(已弃用) v1beta2 X+5 v1、v1beta1(已弃用)、v1beta2(已弃用) v1beta2 v1beta2 被弃用,发布说明中包含对应的 "action required(采取行动)" 说明 X+6 v1、v1beta2(已弃用) v1 v1beta1 被去除,发布说明中包含对应的 "action required(采取行动)" 说明 X+7 v1、v1beta2(已弃用) v1 X+8 v2alpha1、v1 v1 v1beta2 被去除,发布说明中包含对应的 "action required(采取行动)" 说明 X+9 v2alpha2、v1 v1 v2alpha1 被删除,发布说明中包含对应的 "action required(采取行动)" 说明 X+10 v2beta1、v1 v1 v2alpha2 被删除,发布说明中包含对应的 "action required(采取行动)" 说明 X+11 v2beta2、v2beta1(已弃用)、v1 v1 v2beta1 被弃用,发布说明中包含对应的 "action required(采取行动)" 说明 X+12 v2、v2beta2(已弃用)、v2beta1(已弃用)、v1(已弃用) v1 v2beta2 已被弃用,发布说明中包含对应的 "action required(采取行动)" 说明 v1 已被弃用,发布说明中包含对应的 "action required(采取行动)" 说明 X+13 v2、v2beta1(已弃用)、v2beta2(已弃用)、v1(已弃用) v2 X+14 v2、v2beta2(已弃用)、v1(已弃用) v2 v2beta1 被删除,发布说明中包含对应的 "action required(采取行动)" 说明 X+15 v2、v1(已弃用) v2 v2beta2 被删除,发布说明中包含对应的 "action required(采取行动)" 说明 X+16 v2、v1(已弃用) v2 X+17 v2 v2 v1 被删除,发布说明中包含对应的 "action required(采取行动)" 说明
REST 资源(也即 API 对象) 考虑一个假想的名为 Widget 的 REST 资源,在上述时间线中位于 API v1,
而现在打算将其弃用。
我们会在文档和
声明
中与 X+1 版本的发布同步记述此弃用决定。
Wdiget 资源仍会在 API 版本 v1(已弃用)中存在,但不会出现在 v2alpha1 中。
Widget 资源会 X+8 发布版本之前(含 X+8)一直存在并可用。
只有在发布版本 X+9 中,API v1 寿终正寝时,Widget
才彻底消失,相应的资源行为也被移除。
从 Kubernetes v1.19 开始,当 API 请求被发送到一个已弃用的 REST API 末端时:
API 响应中会包含一个 Warning 头部字段(如 RFC7234 5.5 节 所定义);
该请求会导致对应的
审计事件
中会增加一个注解 "k8s.io/deprecated":"true"。
kube-apiserver 进程的 apiserver_requested_deprecated_apis 度量值会被
设置为 1。
该度量值还附带 group、version、resource 和 subresource 标签
(可供添加到度量值 apiserver_request_total 上),
和一个 removed_release 标签,标明该 API 将消失的 Kubernetes 发布版本。
下面的 Prometheus 查询会返回对 v1.22 中将移除的、已弃用的 API
的请求的信息:
apiserver_requested_deprecated_apis {removed_release = "1.22 "} * on ( group ,version ,resource ,subresource ) group_right () apiserver_request_total
REST 资源的字段 就像整个 REST 资源一样,在 API v1 中曾经存在的各个字段在 API v1 被移除
之前必须一直存在且起作用。
与整个资源上的规定不同,v2 API 可以选择为字段提供不同的表示方式,
只要对应的资源对象可在不同版本之间来回转换即可。
例如,v1 版本中一个名为 "magnitude" 的已弃用字段可能在 API v2 中被命名
为 "deprecatedMagnitude"。当 v1 最终被移除时,废弃的字段也可以从 v2
中移除。
枚举值或常数值 就像前文讲述的 REST 资源及其中的单个字段一样,API v1 中所支持的常数值
必须在 API v1 被移除之前一直存在且起作用。
组件配置结构 组件的配置也是有版本的,并且按 REST 资源的方式来管理。
将来的工作 随着时间推移,Kubernetes 会引入粒度更细的 API 版本。
到那时,这里的规则会根据需要进行调整。
弃用一个标志或 CLI 命令 Kubernetes 系统中包含若干不同的、相互协作的程序。
有时,Kubernetes 可能会删除这些程序的某些标志或 CLI 命令(统称“命令行元素”)。
这些程序可以天然地划分到两个大组中:面向用户的和面向管理员的程序。
二者之间的弃用策略略有不同。
除非某个标志显示地通过前缀或文档来标明其为“alpha”或“beta”,
该标志要被视作正式发布的(GA)。
命令行元素相当于系统的 API 的一部分,不过因为它们并没有采用 REST API
一样的方式来管理版本,其弃用规则规定如下:
规则 #5a:面向用户的命令行元素(例如,kubectl)必须在其宣布被弃用其
在以下时长内仍能使用:
GA:12 个月或者 2 个发布版本(取其较长者) Beta:3 个月或者 1 个发布版本(取其较长者) Alpha:0 发布版本 规则 #5b:面向管理员的命令行元素(例如,kubelet)必须在其被宣布弃用
之后以下时长内保持可用:
GA:6 个月或 1 个发行版本(取其较长者) Beta: 3 个月或 1 个发行版本(取其较长者) Alpha: 0 个发布版本 规则 #6:被弃用的 CLI 元素在被用到时必须能够产生警告,而警告的
产生是可以被禁止的。
弃用某功能特性或行为 在一些较偶然的情形下,某 Kubernetes 发行版本需要弃用系统的某项功能
特性或者行为,而对应的功能特性或行为并不受 API 或 CLI 控制。在这种情况下,
其弃用规则如下:
规则 #7:被弃用的行为必须在被宣布弃用之后至少 1 年时间内必须保持能用。
这并不意味着对系统的所有更改都受此策略约束。
此规则仅适用于重大的、用户可见的行为;这些行为会影响到在 Kubernetes
中运行的应用的正确性,或者影响到 Kubernetes 集群的管理。
此规则也适用于那些被整个移除的功能特性或行为。
上述规则的一个例外是 特性门控(Feature Gates) 。特性门控是一些键值偶对,
允许用户启用或禁用一些试验性的功能特性。
特性门控意在覆盖功能特性的整个开发周期,它们无意成为长期的 API。
因此,它们会在某功能特性正式发布或被抛弃之后被弃用和删除。
随着一个功能特性经过不同的成熟阶段,相关的特性门控也会演化。
与功能特性生命周期对应的特性门控状态为:
Alpha:特性门控默认被禁用,只能由用户显式启用。 Beta:特性门控默认被弃用,可被用户显式禁用。 GA: 特性门控被弃用(参见弃用 ),并且不再起作用。 GA,弃用窗口期结束:特性门控被删除,不再接受调用。 弃用 功能特性在正式发布之前的生命周期内任何时间点都可被移除。
当未正式发布的功能特性被移除时,它们对应的特性门控也被弃用。
当尝试禁用一个不再起作用的特性门控时,该调用会失败,这样可以避免
毫无迹象地执行一些不受支持的场景。
在某些场合,移除一个即将正式发布的功能特性需要很长时间。特性门控
可以保持其功能,直到对应的功能特性被彻底去除,直到那时特性门控
自身才可被弃用。
由于移除一个已经正式发布的功能特性对应的特性门控也需要一定时间,对特性
门控的调用可能一直被允许,前提是特性门控对功能本身无影响且特性门控不会
引发任何错误。
意在允许用户禁用的功能特性应该包含一个在相关联的特性门控中禁用该功能的机制。
特性门控的版本管理与之前讨论的组件版本管理不同,因此其对应的弃用策略如下:
规则 #8:特性门控所对应的功能特性经历下面所列的成熟性阶段转换时,特性门控
必须被弃用。特性门控弃用时必须在以下时长内保持其功能可用:
Beta 特性转为 GA:6 个月或者 2 个发布版本(取其较长者) Beta 特性转为丢弃:3 个月或者 1 个发布版本(取其较长者) Alpha 特性转为丢弃:0 个发布版本 规则 #9:已弃用的特色门控再被使用时必须给出警告回应。当特性门控被
弃用时,必须在发布说明和对应的 CLI 帮助信息中通过文档宣布。
警告信息和文档都要标明是否某特性门控不再起作用。
例外 没有策略可以覆盖所有情况。此策略文档是一个随时被更新的文档,会随着时间
推移演化。在实践中,会有一些情况无法很好地匹配到这里的弃用策略,或者
这里的策略变成了很严重的羁绊。这类情形要与 SIG 和项目牵头人讨论,
寻求对应场景的最佳解决方案。请一直铭记,Kubernetes 承诺要成为一个
稳定的系统,至少会尽力做到不会影响到其用户。此弃用策略的任何例外情况
都会在所有相关的发布说明中公布。
6.2.5 - Kubernetes API 健康端点 Kubernetes API 服务器 提供 API 端点以指示 API 服务器的当前状态。
本文描述了这些 API 端点,并说明如何使用。
API 健康端点 Kubernetes API 服务器提供 3 个 API 端点(healthz、livez 和 readyz)来表明 API 服务器的当前状态。
healthz 端点已被弃用(自 Kubernetes v1.16 起),你应该使用更为明确的 livez 和 readyz 端点。
livez 端点可与 --livez-grace-period 标志 一起使用,来指定启动持续时间。
为了正常关机,你可以使用 /readyz 端点并指定 --shutdown-delay-duration 标志 。
检查 API 服务器的 health/livez/readyz 端点的机器应依赖于 HTTP 状态代码。
状态码 200 表示 API 服务器是 healthy、live 还是 ready,具体取决于所调用的端点。
以下更详细的选项供操作人员使用,用来调试其集群或专门调试 API 服务器的状态。
以下示例将显示如何与运行状况 API 端点进行交互。
对于所有端点,都可以使用 verbose 参数来打印检查项以及检查状态。
这对于操作人员调试 API 服务器的当前状态很有用,这些不打算给机器使用:
curl -k https://localhost:6443/livez?verbose
或从具有身份验证的远程主机:
kubectl get --raw= '/readyz?verbose'
输出将如下所示:
[+]ping ok
[+]log ok
[+]etcd ok
[+]poststarthook/start-kube-apiserver-admission-initializer ok
[+]poststarthook/generic-apiserver-start-informers ok
[+]poststarthook/start-apiextensions-informers ok
[+]poststarthook/start-apiextensions-controllers ok
[+]poststarthook/crd-informer-synced ok
[+]poststarthook/bootstrap-controller ok
[+]poststarthook/rbac/bootstrap-roles ok
[+]poststarthook/scheduling/bootstrap-system-priority-classes ok
[+]poststarthook/start-cluster-authentication-info-controller ok
[+]poststarthook/start-kube-aggregator-informers ok
[+]poststarthook/apiservice-registration-controller ok
[+]poststarthook/apiservice-status-available-controller ok
[+]poststarthook/kube-apiserver-autoregistration ok
[+]autoregister-completion ok
[+]poststarthook/apiservice-openapi-controller ok
healthz check passed
Kubernetes API 服务器也支持排除特定的检查项。
查询参数也可以像以下示例一样进行组合:
curl -k 'https://localhost:6443/readyz?verbose&exclude=etcd'
输出显示排除了 etcd 检查:
[+]ping ok
[+]log ok
[+]etcd excluded: ok
[+]poststarthook/start-kube-apiserver-admission-initializer ok
[+]poststarthook/generic-apiserver-start-informers ok
[+]poststarthook/start-apiextensions-informers ok
[+]poststarthook/start-apiextensions-controllers ok
[+]poststarthook/crd-informer-synced ok
[+]poststarthook/bootstrap-controller ok
[+]poststarthook/rbac/bootstrap-roles ok
[+]poststarthook/scheduling/bootstrap-system-priority-classes ok
[+]poststarthook/start-cluster-authentication-info-controller ok
[+]poststarthook/start-kube-aggregator-informers ok
[+]poststarthook/apiservice-registration-controller ok
[+]poststarthook/apiservice-status-available-controller ok
[+]poststarthook/kube-apiserver-autoregistration ok
[+]autoregister-completion ok
[+]poststarthook/apiservice-openapi-controller ok
[+]shutdown ok
healthz check passed
独立健康检查 FEATURE STATE: Kubernetes v1.20 [alpha]
每个单独的健康检查都会公开一个 http 端点,并且可以单独检查。
单个运行状况检查的模式为 /livez/<healthcheck-name>,其中 livez 和 readyz 表明你要检查的是 API 服务器是否存活或就绪。
<healthcheck-name> 的路径可以通过上面的 verbose 参数发现 ,并采用 [+] 和 ok 之间的路径。
这些单独的健康检查不应由机器使用,但对于操作人员调试系统而言,是有帮助的:
curl -k https://localhost:6443/livez/etcd
6.3 - Kubernetes 问题和安全 6.3.1 - Kubernetes 问题追踪 要报告安全问题,请遵循
Kubernetes 安全问题公开流程 。
使用 GitHub Issues
跟踪 Kubernetes 编码工作和公开问题。
与安全性相关的公告请发送到
kubernetes-security-announce@googlegroups.com
邮件列表。
6.3.2 - Kubernetes 安全和信息披露 本页面介绍 Kubernetes 安全和信息披露相关的内容。
安全公告 加入 kubernetes-security-announce 组,以获取关于安全性和主要 API 公告的电子邮件。
你也可以使用此链接 订阅上述的 RSS 反馈。
报告一个漏洞 我们非常感谢向 Kubernetes 开源社区报告漏洞的安全研究人员和用户。
所有的报告都由社区志愿者进行彻底调查。
如需报告,请连同安全细节以及预期的所有 Kubernetes bug 报告
详细信息电子邮件到security@kubernetes.io 列表。
你还可以通过电子邮件向私有 security@kubernetes.io 列表发送电子邮件,邮件中应该包含所有 Kubernetes 错误报告 所需的详细信息。
你可以使用产品安全团队成员
的 GPG 密钥加密你的电子邮件到此列表。使用 GPG 加密不需要公开。
我应该在什么时候报告漏洞? 你认为在 Kubernetes 中发现了一个潜在的安全漏洞 你不确定漏洞如何影响 Kubernetes 你认为你在 Kubernetes 依赖的另一个项目中发现了一个漏洞 对于具有漏洞报告和披露流程的项目,请直接在该项目处报告 我什么时候不应该报告漏洞? 你需要帮助调整 Kubernetes 组件的安全性 你需要帮助应用与安全相关的更新 你的问题与安全无关 安全漏洞响应 每个报告在 3 个工作日内由产品安全团队成员确认和分析。这将启动安全发布过程 。
与产品安全团队共享的任何漏洞信息都保留在 Kubernetes 项目中,除非有必要修复该问题,否则不会传播到其他项目。
随着安全问题从分类、识别修复、发布计划等方面的进展,我们将不断更新报告。
公开披露时间 公开披露日期由 Kubernetes 产品安全团队和 bug 提交者协商。我们倾向于在用户缓解措施可用时尽快完全披露该 bug。
当 bug 或其修复还没有被完全理解,解决方案没有经过良好的测试,或者为了处理供应商协调问题时,延迟披露是合理的。
信息披露的时间范围从即时(尤其是已经公开的)到几周。作为一个基本的约定,我们希望报告日期到披露日期的间隔是 7 天。在设置披露日期时,Kubernetes 产品安全团队拥有最终决定权。
6.4 - 常见的标签、注解和污点 Kubernetes 预留命名空间 kubernetes.io 用于所有的标签和注解。
本文档有两个作用,一是作为可用值的参考,二是作为赋值的协调点。
kubernetes.io/arch 示例:kubernetes.io/arch=amd64
用于:Node
Kubelet 用 Go 定义的 runtime.GOARCH 生成该标签的键值。在混合使用 arm 和 x86 节点的场景中,此键值可以带来极大便利。
kubernetes.io/os 示例:kubernetes.io/os=linux
用于:Node
Kubelet 用 Go 定义的 runtime.GOOS 生成该标签的键值。在混合使用异构操作系统场景下(例如:混合使用 Linux 和 Windows 节点),此键值可以带来极大便利。
beta.kubernetes.io/arch (deprecated) 此标签已被弃用,取而代之的是 kubernetes.io/arch.
beta.kubernetes.io/os (deprecated) 此标签已被弃用,取而代之的是 kubernetes.io/os.
kubernetes.io/hostname 示例:kubernetes.io/hostname=ip-172-20-114-199.ec2.internal
用于:Node
Kubelet 用主机名生成此标签。需要注意的是主机名可修改,这是把“实际的”主机名通过参数 --hostname-override 传给 kubelet 实现的。
此标签也可用做拓扑层次的一个部分。更多信息参见topology.kubernetes.io/zone 。
beta.kubernetes.io/instance-type (deprecated) node.kubernetes.io/instance-type 示例:node.kubernetes.io/instance-type=m3.medium
用于:Node
Kubelet 用 cloudprovider 定义的实例类型生成此标签。
所以只有用到 cloudprovider 的场合,才会设置此标签。
此标签非常有用,特别是在你希望把特定工作负载打到特定实例类型的时候,但更常见的调度方法是基于 Kubernetes 调度器来执行基于资源的调度。
你应该聚焦于使用基于属性的调度方式,而尽量不要依赖实例类型(例如:应该申请一个 GPU,而不是 g2.2xlarge)。
failure-domain.beta.kubernetes.io/region (deprecated) 参见 topology.kubernetes.io/region .
failure-domain.beta.kubernetes.io/zone (deprecated) 参见 topology.kubernetes.io/zone .
topology.kubernetes.io/region 示例
topology.kubernetes.io/region=us-east-1
参见 topology.kubernetes.io/zone .
topology.kubernetes.io/zone 示例:
topology.kubernetes.io/zone=us-east-1c
用于:Node, PersistentVolume
Node 场景:kubelet 或外部的 cloud-controller-manager 用 cloudprovider 提供的信息生成此标签。
所以只有在用到 cloudprovider 的场景下,此标签才会被设置。
但如果此标签在你的拓扑中有意义,你也可以考虑在 node 上设置它。
PersistentVolume 场景:拓扑自感知的卷制备程序将在 PersistentVolumes 上自动设置节点亲和性限制。
一个可用区(zone)表示一个逻辑故障域。Kubernetes 集群通常会跨越多个可用区以提高可用性。
虽然可用区的确切定义留给基础设施来决定,但可用区常见的属性包括:可用区内的网络延迟非常低,可用区内的网络通讯没成本,独立于其他可用区的故障域。
例如,一个可用区中的节点可以共享交换机,但不同可用区则不会。
一个地区(region)表示一个更大的域,由一个到多个可用区组成。对于 Kubernetes 来说,跨越多个地区的集群很罕见。
虽然可用区和地区的确切定义留给基础设施来决定,但地区的常见属性包括:地区间比地区内更高的网络延迟,地区间网络流量更高的成本,独立于其他可用区或是地区的故障域。例如,一个地区内的节点可以共享电力基础设施(例如 UPS 或发电机),但不同地区内的节点显然不会。
Kubernetes 对可用区和地区的结构做出一些假设:
1)地区和可用区是层次化的:可用区是地区的严格子集,任何可用区都不能再 2 个地区中出现。
2)可用区名字在地区中独一无二:例如地区 "africa-east-1" 可由可用区 "africa-east-1a" 和 "africa-east-1b" 构成。
你可以安全的假定拓扑类的标签是固定不变的。即使标签严格来说是可变的,但使用者依然可以假定一个节点只有通过销毁、重建的方式,才能在可用区间移动。
Kubernetes 能以多种方式使用这些信息。
例如,调度器自动地尝试将 ReplicaSet 中的 Pod 打散在单可用区集群的不同节点上(以减少节点故障的影响,参见kubernetes.io/hostname )。
在多可用区的集群中,这类打散分布的行为也会应用到可用区(以减少可用区故障的影响)。
做到这一点靠的是 SelectorSpreadPriority 。
SelectorSpreadPriority 是一种最大能力分配方法(best effort)。如果集群中的可用区是异构的(例如:不同数量的节点,不同类型的节点,或不同的 Pod 资源需求),这种分配方法可以防止平均分配 Pod 到可用区。如果需要,你可以用同构的可用区(相同数量和类型的节点)来减少潜在的不平衡分布。
调度器(通过 VolumeZonePredicate 的预测)也会保障声明了某卷的 Pod 只能分配到该卷相同的可用区。
卷不支持跨可用区挂载。
如果 PersistentVolumeLabel 不支持给 PersistentVolume 自动打标签,你可以考虑手动加标签(或增加 PersistentVolumeLabel 支持)。
有了 PersistentVolumeLabel,调度器可以防止 Pod 挂载不同可用区中的卷。
如果你的基础架构没有此限制,那你根本就没有必要给卷增加 zone 标签。
node.kubernetes.io/windows-build 示例: node.kubernetes.io/windows-build=10.0.17763
用于:Node
当 kubelet 运行于 Microsoft Windows,它给节点自动打标签,以记录 Windows Server 的版本。
标签值的格式为 "主版本.次版本.构建号"
service.kubernetes.io/headless 示例:service.kubernetes.io/headless=""
用于:Service
在无头(headless)服务的场景下,控制平面为 Endpoint 对象添加此标签。
kubernetes.io/service-name 示例:kubernetes.io/service-name="nginx"
用于:Service
Kubernetes 用此标签区分多个服务。当前仅用于 ELB(Elastic Load Balancer)。
endpointslice.kubernetes.io/managed-by 示例:endpointslice.kubernetes.io/managed-by="controller"
用于:EndpointSlices
此标签用来指向管理 EndpointSlice 的控制器或实体。
此标签的目的是用集群中不同的控制器或实体来管理不同的 EndpointSlice。
endpointslice.kubernetes.io/skip-mirror 示例:endpointslice.kubernetes.io/skip-mirror="true"
用于:Endpoints
此标签在 Endpoints 资源上设为 "true" 指示 EndpointSliceMirroring 控制器不要镜像此 EndpointSlices 资源。
service.kubernetes.io/service-proxy-name 示例:service.kubernetes.io/service-proxy-name="foo-bar"
用于:Service
kube-proxy 把此标签用于客户代理,将服务控制委托给客户代理。
experimental.windows.kubernetes.io/isolation-type 示例:experimental.windows.kubernetes.io/isolation-type: "hyperv"
用于:Pod
此注解用于运行 Hyper-V 隔离的 Windows 容器。
要使用 Hyper-V 隔离特性,并创建 Hyper-V 隔离容器,kubelet 应该用特性门控 HyperVContainer=true 来启动,并且 Pod 应该包含注解 experimental.windows.kubernetes.io/isolation-type=hyperv。
说明: 你只能在单容器 Pod 上设置此注解。
ingressclass.kubernetes.io/is-default-class 示例:ingressclass.kubernetes.io/is-default-class: "true"
用于:IngressClass
当唯一的 IngressClass 资源将此注解的值设为 "true",没有指定类型的新 Ingress 资源将使用此默认类型。
kubernetes.io/ingress.class (deprecated) 说明: 从 v1.18 开始,此注解被弃用,取而代之的是 spec.ingressClassName。
alpha.kubernetes.io/provided-node-ip 示例:alpha.kubernetes.io/provided-node-ip: "10.0.0.1"
用于:Node
kubectl 在 Node 上设置此注解,表示它的 IPv4 地址。
当 kubectl 由外部的云供应商启动时,在 Node 上设置此注解,表示由命令行标记(--node-ip)设置的 IP 地址。
cloud-controller-manager 向云供应商验证此 IP 是否有效。
以下列出的污点只能用于 Node
node.kubernetes.io/not-ready 示例:node.kubernetes.io/not-ready:NoExecute
节点控制器通过健康监控来检测节点是否就绪,并据此添加/删除此污点。
node.kubernetes.io/unreachable 示例:node.kubernetes.io/unreachable:NoExecute
如果 NodeCondition 的 Ready 键值为 Unknown,节点控制器将添加污点到 node。
node.kubernetes.io/unschedulable 示例:node.kubernetes.io/unschedulable:NoSchedule
当初始化节点时,添加此污点,来避免竟态的发生。
node.kubernetes.io/memory-pressure 示例:node.kubernetes.io/memory-pressure:NoSchedule
kubelet 依据节点上观测到的 memory.available 和 allocatableMemory.available 来检测内存压力。
用观测值对比 kubelet 设置的阈值,以判断节点状态和污点是否可以被添加/移除。
node.kubernetes.io/disk-pressure 示例:node.kubernetes.io/disk-pressure:NoSchedule
kubelet 依据节点上观测到的 imagefs.available、imagefs.inodesFree、nodefs.available 和 nodefs.inodesFree(仅 Linux) 来判断磁盘压力。
用观测值对比 kubelet 设置的阈值,以确定节点状态和污点是否可以被添加/移除。
node.kubernetes.io/network-unavailable 示例:node.kubernetes.io/network-unavailable:NoSchedule
它初始由 kubectl 设置,云供应商用它来指示对额外网络配置的需求。
仅当云中的路由器配置妥当后,云供应商才会移除此污点。
node.kubernetes.io/pid-pressure 示例:node.kubernetes.io/pid-pressure:NoSchedule
kubelet 检查 /proc/sys/kernel/pid_max 尺寸的 D 值(D-value),以及节点上 Kubernetes 消耗掉的 PID,以获取可用的 PID 数量,此数量可通过指标 pid.available 得到。
然后用此指标对比 kubelet 设置的阈值,以确定节点状态和污点是否可以被添加/移除。
node.cloudprovider.kubernetes.io/uninitialized 示例:node.cloudprovider.kubernetes.io/uninitialized:NoSchedule
当 kubelet 由外部云供应商启动时,在节点上设置此污点以标记节点不可用,直到一个 cloud-controller-manager 控制器初始化此节点之后,才会移除此污点。
node.cloudprovider.kubernetes.io/shutdown 示例:node.cloudprovider.kubernetes.io/shutdown:NoSchedule
如果一个云供应商的节点被指定为关机状态,节点被打上污点 node.cloudprovider.kubernetes.io/shutdown,污点的影响为 NoSchedule。
6.5 - 访问 API 关于 Kubernetes 如何实现和控制 API 访问的介绍性材料,可阅读
控制 Kubernetes API 的访问 。
参考文档:
6.5.1 - 用户认证 本页提供身份认证有关的概述。
Kubernetes 中的用户 所有 Kubernetes 集群都有两类用户:由 Kubernetes 管理的服务账号和普通用户。
Kubernetes 假定普通用户是由一个与集群无关的服务通过以下方式之一进行管理的:
负责分发私钥的管理员 类似 Keystone 或者 Google Accounts 这类用户数据库 包含用户名和密码列表的文件 有鉴于此,Kubernetes 并不包含用来代表普通用户账号的对象 。
普通用户的信息无法通过 API 调用添加到集群中。
尽管无法通过 API 调用来添加普通用户,Kubernetes 仍然认为能够提供由集群的证书
机构签名的合法证书的用户是通过身份认证的用户。基于这样的配置,Kubernetes
使用证书中的 'subject' 的通用名称(Common Name)字段(例如,"/CN=bob")来
确定用户名。接下来,基于角色访问控制(RBAC)子系统会确定用户是否有权针对
某资源执行特定的操作。进一步的细节可参阅
证书请求
下普通用户主题。
与此不同,服务账号是 Kubernetes API 所管理的用户。它们被绑定到特定的名字空间,
或者由 API 服务器自动创建,或者通过 API 调用创建。服务账号与一组以 Secret 保存
的凭据相关,这些凭据会被挂载到 Pod 中,从而允许集群内的进程访问 Kubernetes
API。
API 请求则或者与某普通用户相关联,或者与某服务账号相关联,亦或者被视作
匿名请求 。这意味着集群内外的每个进程在向 API 服务器发起
请求时都必须通过身份认证,否则会被视作匿名用户。这里的进程可以是在某工作站上
输入 kubectl 命令的操作人员,也可以是节点上的 kubelet 组件,还可以是控制面
的成员。
身份认证策略 Kubernetes 使用身份认证插件利用客户端证书、持有者令牌(Bearer Token)、身份认证代理(Proxy)
或者 HTTP 基本认证机制来认证 API 请求的身份。HTTP 请求发给 API 服务器时,
插件会将以下属性关联到请求本身:
用户名:用来辩识最终用户的字符串。常见的值可以是 kube-admin 或 jane@example.com。 用户 ID:用来辩识最终用户的字符串,旨在比用户名有更好的一致性和唯一性。 用户组:取值为一组字符串,其中各个字符串用来标明用户是某个命名的用户逻辑集合的成员。
常见的值可能是 system:masters 或者 devops-team 等。 附加字段:一组额外的键-值映射,键是字符串,值是一组字符串;用来保存一些鉴权组件可能
觉得有用的额外信息。 所有(属性)值对于身份认证系统而言都是不透明的,只有被
鉴权组件
解释过之后才有意义。
你可以同时启用多种身份认证方法,并且你通常会至少使用两种方法:
针对服务账号使用服务账号令牌 至少另外一种方法对用户的身份进行认证 当集群中启用了多个身份认证模块时,第一个成功地对请求完成身份认证的模块会
直接做出评估决定。API 服务器并不保证身份认证模块的运行顺序。
对于所有通过身份认证的用户,system:authenticated 组都会被添加到其组列表中。
与其它身份认证协议(LDAP、SAML、Kerberos、X509 的替代模式等等)都可以通过
使用一个身份认证代理 或
身份认证 Webhoook 来实现。
X509 客户证书 通过给 API 服务器传递 --client-ca-file=SOMEFILE 选项,就可以启动客户端证书身份认证。
所引用的文件必须包含一个或者多个证书机构,用来验证向 API 服务器提供的客户端证书。
如果提供了客户端证书并且证书被验证通过,则 subject 中的公共名称(Common Name)就被
作为请求的用户名。
自 Kubernetes 1.4 开始,客户端证书还可以通过证书的 organization 字段标明用户的组成员信息。
要包含用户的多个组成员信息,可以在证书种包含多个 organization 字段。
例如,使用 openssl 命令行工具生成一个证书签名请求:
openssl req -new -key jbeda.pem -out jbeda-csr.pem -subj "/CN=jbeda/O=app1/O=app2"
此命令将使用用户名 jbeda 生成一个证书签名请求(CSR),且该用户属于 "app" 和
"app2" 两个用户组。
参阅管理证书 了解如何生成客户端证书。
静态令牌文件 当 API 服务器的命令行设置了 --token-auth-file=SOMEFILE 选项时,会从文件中
读取持有者令牌。目前,令牌会长期有效,并且在不重启 API 服务器的情况下
无法更改令牌列表。
令牌文件是一个 CSV 文件,包含至少 3 个列:令牌、用户名和用户的 UID。
其余列被视为可选的组名。
说明: 如果要设置的组名不止一个,则对应的列必须用双引号括起来,例如
token,user,uid,"group1,group2,group3"
在请求中放入持有者令牌 当使用持有者令牌来对某 HTTP 客户端执行身份认证时,API 服务器希望看到
一个名为 Authorization 的 HTTP 头,其值格式为 Bearer THETOKEN。
持有者令牌必须是一个可以放入 HTTP 头部值字段的字符序列,至多可使用
HTTP 的编码和引用机制。
例如:如果持有者令牌为 31ada4fd-adec-460c-809a-9e56ceb75269,则其
出现在 HTTP 头部时如下所示:
Authorization: Bearer 31ada4fd-adec-460c-809a-9e56ceb75269
启动引导令牌 FEATURE STATE: Kubernetes v1.18 [stable]
为了支持平滑地启动引导新的集群,Kubernetes 包含了一种动态管理的持有者令牌类型,
称作 启动引导令牌(Bootstrap Token) 。
这些令牌以 Secret 的形式保存在 kube-system 名字空间中,可以被动态管理和创建。
控制器管理器包含的 TokenCleaner 控制器能够在启动引导令牌过期时将其删除。
这些令牌的格式为 [a-z0-9]{6}.[a-z0-9]{16}。第一个部分是令牌的 ID;第二个部分
是令牌的 Secret。你可以用如下所示的方式来在 HTTP 头部设置令牌:
Authorization: Bearer 781292.db7bc3a58fc5f07e
你必须在 API 服务器上设置 --enable-bootstrap-token-auth 标志来启用基于启动
引导令牌的身份认证组件。
你必须通过控制器管理器的 --controllers 标志来启用 TokenCleaner 控制器;
这可以通过类似 --controllers=*,tokencleaner 这种设置来做到。
如果你使用 kubeadm 来启动引导新的集群,该工具会帮你完成这些设置。
身份认证组件的认证结果为 system:bootstrap:<令牌 ID>,该用户属于
system:bootstrappers 用户组。
这里的用户名和组设置都是有意设计成这样,其目的是阻止用户在启动引导集群之后
继续使用这些令牌。
这里的用户名和组名可以用来(并且已经被 kubeadm 用来)构造合适的鉴权
策略,以完成启动引导新集群的工作。
请参阅启动引导令牌
以了解关于启动引导令牌身份认证组件与控制器的更深入的信息,以及如何使用
kubeadm 来管理这些令牌。
服务账号令牌 服务账号(Service Account)是一种自动被启用的用户认证机制,使用经过签名的
持有者令牌来验证请求。该插件可接受两个可选参数:
--service-account-key-file 一个包含用来为持有者令牌签名的 PEM 编码密钥。
若未指定,则使用 API 服务器的 TLS 私钥。--service-account-lookup 如果启用,则从 API 删除的令牌会被回收。服务账号通常由 API 服务器自动创建并通过 ServiceAccount
准入控制器
关联到集群中运行的 Pod 上。
持有者令牌会挂载到 Pod 中可预知的位置,允许集群内进程与 API 服务器通信。
服务账号也可以使用 Pod 规约的 serviceAccountName 字段显式地关联到 Pod 上。
说明: serviceAccountName 通常会被忽略,因为关联关系是自动建立的。
apiVersion : apps/v1
kind : Deployment
metadata :
name : nginx-deployment
namespace : default
spec :
replicas : 3
template :
metadata :
# ...
spec :
serviceAccountName : bob-the-bot
containers :
- name : nginx
image : nginx:1.14.2
在集群外部使用服务账号持有者令牌也是完全合法的,且可用来为长时间运行的、需要与
Kubernetes API 服务器通信的任务创建标识。要手动创建服务账号,可以使用
kubectl create serviceaccount <名称> 命令。此命令会在当前的名字空间中生成一个
服务账号和一个与之关联的 Secret。
kubectl create serviceaccount jenkins
serviceaccount/jenkins created
查验相关联的 Secret:
kubectl get serviceaccounts jenkins -o yaml
apiVersion : v1
kind : ServiceAccount
metadata :
# ...
secrets :
- name : jenkins-token-1yvwg
所创建的 Secret 中会保存 API 服务器的公开的 CA 证书和一个已签名的 JSON Web
令牌(JWT)。
kubectl get secret jenkins-token-1yvwg -o yaml
apiVersion : v1
data :
ca.crt : <Base64 编码的 API 服务器 CA>
namespace : ZGVmYXVsdA==
token : <Base64 编码的持有者令牌>
kind : Secret
metadata :
# ...
type : kubernetes.io/service-account-token
说明: 字段值是按 Base64 编码的,这是因为 Secret 数据总是采用 Base64 编码来存储。
已签名的 JWT 可以用作持有者令牌,并将被认证为所给的服务账号。
关于如何在请求中包含令牌,请参阅前文 。
通常,这些 Secret 数据会被挂载到 Pod 中以便集群内访问 API 服务器时使用,
不过也可以在集群外部使用。
服务账号被身份认证后,所确定的用户名为 system:serviceaccount:<名字空间>:<服务账号>,
并被分配到用户组 system:serviceaccounts 和 system:serviceaccounts:<名字空间>。
警告:由于服务账号令牌保存在 Secret 对象中,任何能够读取这些 Secret 的用户
都可以被认证为对应的服务账号。在为用户授予访问服务账号的权限时,以及对 Secret
的读权限时,要格外小心。
OpenID Connect(OIDC)令牌 OpenID Connect 是一种 OAuth2 认证方式,
被某些 OAuth2 提供者支持,例如 Azure 活动目录、Salesforce 和 Google。
协议对 OAuth2 的主要扩充体现在有一个附加字段会和访问令牌一起返回,
这一字段称作 ID Token(ID 令牌) 。
ID 令牌是一种由服务器签名的 JSON Web 令牌(JWT),其中包含一些可预知的字段,
例如用户的邮箱地址,
要识别用户,身份认证组件使用 OAuth2
令牌响应
中的 id_token(而非 access_token)作为持有者令牌。
关于如何在请求中设置令牌,可参见前文 。
sequenceDiagram
participant user as 用户
participant idp as 身份提供者
participant kube as Kubectl
participant api as API 服务器
user ->> idp: 1. 登录到 IdP
activate idp
idp -->> user: 2. 提供 access_token, id_token, 和 refresh_token
deactivate idp
activate user
user ->> kube: 3. 调用 Kubectl 并 设置 --token 为 id_token 或者将令牌添加到 .kube/config
deactivate user
activate kube
kube ->> api: 4. Authorization: Bearer...
deactivate kube
activate api
api ->> api: 5. JWT 签名合法么?
api ->> api: 6. JWT 是否已过期?(iat+exp)
api ->> api: 7. 用户被授权了么?
api -->> kube: 8. 已授权:执行 操作并返回结果
deactivate api
activate kube
kube --x user: 9. 返回结果
deactivate kube
[JavaScript must be enabled to view content] 登录到你的身份服务(Identity Provider) 你的身份服务将为你提供 access_token、id_token 和 refresh_token 在使用 kubectl 时,将 id_token 设置为 --token 标志值,或者将其直接添加到
kubeconfig 中 kubectl 将你的 id_token 放到一个称作 Authorization 的头部,发送给 API 服务器API 服务器将负责通过检查配置中引用的证书来确认 JWT 的签名是合法的 检查确认 id_token 尚未过期 确认用户有权限执行操作 鉴权成功之后,API 服务器向 kubectl 返回响应 kubectl 向用户提供反馈信息由于用来验证你是谁的所有数据都在 id_token 中,Kubernetes 不需要再去联系
身份服务。在一个所有请求都是无状态请求的模型中,这一工作方式可以使得身份认证
的解决方案更容易处理大规模请求。不过,此访问也有一些挑战:
Kubernetes 没有提供用来触发身份认证过程的 "Web 界面"。
因为不存在用来收集用户凭据的浏览器或用户接口,你必须自己先行完成
对身份服务的认证过程。 id_token 令牌不可收回。因其属性类似于证书,其生命期一般很短(只有几分钟),
所以,每隔几分钟就要获得一个新的令牌这件事可能很让人头疼。如果不使用 kubectl proxy 命令或者一个能够注入 id_token 的反向代理,
向 Kubernetes 控制面板执行身份认证是很困难的。 配置 API 服务器 要启用此插件,须在 API 服务器上配置以下标志:
参数 描述 示例 必需? --oidc-issuer-url允许 API 服务器发现公开的签名密钥的服务的 URL。只接受模式为 https:// 的 URL。此值通常设置为服务的发现 URL,不含路径。例如:"https://accounts.google.com" 或 "https://login.salesforce.com"。此 URL 应指向 .well-known/openid-configuration 下一层的路径。 如果发现 URL 是 https://accounts.google.com/.well-known/openid-configuration,则此值应为 https://accounts.google.com 是 --oidc-client-id所有令牌都应发放给此客户 ID。 kubernetes 是 --oidc-username-claim用作用户名的 JWT 申领(JWT Claim)。默认情况下使用 sub 值,即最终用户的一个唯一的标识符。管理员也可以选择其他申领,例如 email 或者 name,取决于所用的身份服务。不过,除了 email 之外的申领都会被添加令牌发放者的 URL 作为前缀,以免与其他插件产生命名冲突。 sub 否 --oidc-username-prefix要添加到用户名申领之前的前缀,用来避免与现有用户名发生冲突(例如:system: 用户)。例如,此标志值为 oidc: 时将创建形如 oidc:jane.doe 的用户名。如果此标志未设置,且 --oidc-username-claim 标志值不是 email,则默认前缀为 <令牌发放者的 URL>#,其中 <令牌发放者 URL > 的值取自 --oidc-issuer-url 标志的设定。此标志值为 - 时,意味着禁止添加用户名前缀。 oidc:否 --oidc-groups-claim用作用户组名的 JWT 申领。如果所指定的申领确实存在,则其值必须是一个字符串数组。 groups 否 --oidc-groups-prefix添加到组申领的前缀,用来避免与现有用户组名(如:system: 组)发生冲突。例如,此标志值为 oidc: 时,所得到的用户组名形如 oidc:engineering 和 oidc:infra。 oidc:否 --oidc-required-claim取值为一个 key=value 偶对,意为 ID 令牌中必须存在的申领。如果设置了此标志,则 ID 令牌会被检查以确定是否包含取值匹配的申领。此标志可多次重复,以指定多个申领。 claim=value否 --oidc-ca-file指向一个 CA 证书的路径,该 CA 负责对你的身份服务的 Web 证书提供签名。默认值为宿主系统的根 CA。 /etc/kubernetes/ssl/kc-ca.pem否
很重要的一点是,API 服务器并非一个 OAuth2 客户端,相反,它只能被配置为
信任某一个令牌发放者。这使得使用公共服务(如 Google)的用户可以不信任发放给
第三方的凭据。
如果管理员希望使用多个 OAuth 客户端,他们应该研究一下那些支持 azp
(Authorized Party,被授权方)申领的服务。
azp 是一种允许某客户端代替另一客户端发放令牌的机制。
Kubernetes 并未提供 OpenID Connect 的身份服务。
你可以使用现有的公共的 OpenID Connect 身份服务(例如 Google 或者
其他服务 )。
或者,你也可以选择自己运行一个身份服务,例如
CoreOS dex 、
Keycloak 、
CloudFoundry UAA 或者
Tremolo Security 的
OpenUnison 。
要在 Kubernetes 环境中使用某身份服务,该服务必须:
支持 OpenID connect 发现 ;
但事实上并非所有服务都具备此能力 运行 TLS 协议且所使用的加密组件都未过时 拥有由 CA 签名的证书(即使 CA 不是商业 CA 或者是自签名的 CA 也可以) 关于上述第三条需求,即要求具备 CA 签名的证书,有一些额外的注意事项。
如果你部署了自己的身份服务,而不是使用云厂商(如 Google 或 Microsoft)所提供的服务,
你必须对身份服务的 Web 服务器证书进行签名,签名所用证书的 CA 标志要设置为
TRUE,即使用的是自签名证书。这是因为 GoLang 的 TLS 客户端实现对证书验证
标准方面有非常严格的要求。如果你手头没有现成的 CA 证书,可以使用 CoreOS
团队所开发的这个脚本
来创建一个简单的 CA 和被签了名的证书与密钥对。
或者你也可以使用
这个类似的脚本 ,
生成一个合法期更长、密钥尺寸更大的 SHA256 证书。
特定系统的安装指令:
使用 kubectl 选项一 - OIDC 身份认证组件 第一种方案是使用 kubectl 的 oidc 身份认证组件,该组件将 id_token 设置
为所有请求的持有者令牌,并且在令牌过期时自动刷新。在你登录到你的身份服务之后,
可以使用 kubectl 来添加你的 id_token、refresh_token、client_id 和
client_secret,以配置该插件。
如果服务在其刷新令牌响应中不包含 id_token,则此插件无法支持该服务。
这时你应该考虑下面的选项二。
kubectl config set-credentials USER_NAME \
--auth-provider= oidc \
--auth-provider-arg= idp-issuer-url=( issuer url ) \
--auth-provider-arg= client-id=( your client id ) \
--auth-provider-arg= client-secret=( your client secret ) \
--auth-provider-arg= refresh-token=( your refresh token ) \
--auth-provider-arg= idp-certificate-authority=( path to your ca certificate ) \
--auth-provider-arg= id-token=( your id_token )
作为示例,在完成对你的身份服务的身份认证之后,运行下面的命令:
kubectl config set-credentials mmosley \
--auth-provider= oidc \
--auth-provider-arg= idp-issuer-url= https://oidcidp.tremolo.lan:8443/auth/idp/OidcIdP \
--auth-provider-arg= client-id= kubernetes \
--auth-provider-arg= client-secret= 1db158f6-177d-4d9c-8a8b-d36869918ec5 \
--auth-provider-arg= refresh-token= q1bKLFOyUiosTfawzA93TzZIDzH2TNa2SMm0zEiPKTUwME6BkEo6Sql5yUWVBSWpKUGphaWpxSVAfekBOZbBhaEW+VlFUeVRGcluyVF5JT4+haZmPsluFoFu5XkpXk5BXqHega4GAXlF+ma+vmYpFcHe5eZR+slBFpZKtQA= \
--auth-provider-arg= idp-certificate-authority= /root/ca.pem \
--auth-provider-arg= id-token= eyJraWQiOiJDTj1vaWRjaWRwLnRyZW1vbG8ubGFuLCBPVT1EZW1vLCBPPVRybWVvbG8gU2VjdXJpdHksIEw9QXJsaW5ndG9uLCBTVD1WaXJnaW5pYSwgQz1VUy1DTj1rdWJlLWNhLTEyMDIxNDc5MjEwMzYwNzMyMTUyIiwiYWxnIjoiUlMyNTYifQ.eyJpc3MiOiJodHRwczovL29pZGNpZHAudHJlbW9sby5sYW46ODQ0My9hdXRoL2lkcC9PaWRjSWRQIiwiYXVkIjoia3ViZXJuZXRlcyIsImV4cCI6MTQ4MzU0OTUxMSwianRpIjoiMm96US15TXdFcHV4WDlHZUhQdy1hZyIsImlhdCI6MTQ4MzU0OTQ1MSwibmJmIjoxNDgzNTQ5MzMxLCJzdWIiOiI0YWViMzdiYS1iNjQ1LTQ4ZmQtYWIzMC0xYTAxZWU0MWUyMTgifQ.w6p4J_6qQ1HzTG9nrEOrubxIMb9K5hzcMPxc9IxPx2K4xO9l-oFiUw93daH3m5pluP6K7eOE6txBuRVfEcpJSwlelsOsW8gb8VJcnzMS9EnZpeA0tW_p-mnkFc3VcfyXuhe5R3G7aa5d8uHv70yJ9Y3-UhjiN9EhpMdfPAoEB9fYKKkJRzF7utTTIPGrSaSU6d2pcpfYKaxIwePzEkT4DfcQthoZdy9ucNvvLoi1DIC-UocFD8HLs8LYKEqSxQvOcvnThbObJ9af71EwmuE21fO5KzMW20KtAeget1gnldOosPtz1G5EwvaQ401-RPQzPGMVBld0_zMCAwZttJ4knw
此操作会生成以下配置:
users :
- name : mmosley
user :
auth-provider :
config :
client-id : kubernetes
client-secret : 1db158f6-177d-4d9c-8a8b-d36869918ec5
id-token : eyJraWQiOiJDTj1vaWRjaWRwLnRyZW1vbG8ubGFuLCBPVT1EZW1vLCBPPVRybWVvbG8gU2VjdXJpdHksIEw9QXJsaW5ndG9uLCBTVD1WaXJnaW5pYSwgQz1VUy1DTj1rdWJlLWNhLTEyMDIxNDc5MjEwMzYwNzMyMTUyIiwiYWxnIjoiUlMyNTYifQ.eyJpc3MiOiJodHRwczovL29pZGNpZHAudHJlbW9sby5sYW46ODQ0My9hdXRoL2lkcC9PaWRjSWRQIiwiYXVkIjoia3ViZXJuZXRlcyIsImV4cCI6MTQ4MzU0OTUxMSwianRpIjoiMm96US15TXdFcHV4WDlHZUhQdy1hZyIsImlhdCI6MTQ4MzU0OTQ1MSwibmJmIjoxNDgzNTQ5MzMxLCJzdWIiOiI0YWViMzdiYS1iNjQ1LTQ4ZmQtYWIzMC0xYTAxZWU0MWUyMTgifQ.w6p4J_6qQ1HzTG9nrEOrubxIMb9K5hzcMPxc9IxPx2K4xO9l-oFiUw93daH3m5pluP6K7eOE6txBuRVfEcpJSwlelsOsW8gb8VJcnzMS9EnZpeA0tW_p-mnkFc3VcfyXuhe5R3G7aa5d8uHv70yJ9Y3-UhjiN9EhpMdfPAoEB9fYKKkJRzF7utTTIPGrSaSU6d2pcpfYKaxIwePzEkT4DfcQthoZdy9ucNvvLoi1DIC-UocFD8HLs8LYKEqSxQvOcvnThbObJ9af71EwmuE21fO5KzMW20KtAeget1gnldOosPtz1G5EwvaQ401-RPQzPGMVBld0_zMCAwZttJ4knw
idp-certificate-authority : /root/ca.pem
idp-issuer-url : https://oidcidp.tremolo.lan:8443/auth/idp/OidcIdP
refresh-token : q1bKLFOyUiosTfawzA93TzZIDzH2TNa2SMm0zEiPKTUwME6BkEo6Sql5yUWVBSWpKUGphaWpxSVAfekBOZbBhaEW+VlFUeVRGcluyVF5JT4+haZmPsluFoFu5XkpXk5BXq
name : oidc
当你的 id_token 过期时,kubectl 会尝试使用你的 refresh_token 来刷新你的
id_token,并且在 client_secret 中存放 refresh_token 的新值,同时把
id_token 的新值写入到 .kube/config 文件中。
选项二 - 使用 --token 选项 kubectl 命令允许你使用 --token 选项传递一个令牌。
你可以将 id_token 的内容复制粘贴过来,作为此标志的取值:
kubectl --token= eyJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJodHRwczovL21sYi50cmVtb2xvLmxhbjo4MDQzL2F1dGgvaWRwL29pZGMiLCJhdWQiOiJrdWJlcm5ldGVzIiwiZXhwIjoxNDc0NTk2NjY5LCJqdGkiOiI2RDUzNXoxUEpFNjJOR3QxaWVyYm9RIiwiaWF0IjoxNDc0NTk2MzY5LCJuYmYiOjE0NzQ1OTYyNDksInN1YiI6Im13aW5kdSIsInVzZXJfcm9sZSI6WyJ1c2VycyIsIm5ldy1uYW1lc3BhY2Utdmlld2VyIl0sImVtYWlsIjoibXdpbmR1QG5vbW9yZWplZGkuY29tIn0.f2As579n9VNoaKzoF-dOQGmXkFKf1FMyNV0-va_B63jn-_n9LGSCca_6IVMP8pO-Zb4KvRqGyTP0r3HkHxYy5c81AnIh8ijarruczl-TK_yF5akjSTHFZD-0gRzlevBDiH8Q79NAr-ky0P4iIXS8lY9Vnjch5MF74Zx0c3alKJHJUnnpjIACByfF2SCaYzbWFMUNat-K1PaUk5-ujMBG7yYnr95xD-63n8CO8teGUAAEMx6zRjzfhnhbzX-ajwZLGwGUBT4WqjMs70-6a7_8gZmLZb2az1cZynkFRj2BaCkVT3A2RrjeEwZEtGXlMqKJ1_I2ulrOVsYx01_yD35-rw get nodes
Webhook 令牌身份认证 Webhook 身份认证是一种用来验证持有者令牌的回调机制。
--authentication-token-webhook-config-file 指向一个配置文件,其中描述
如何访问远程的 Webhook 服务。--authentication-token-webhook-cache-ttl 用来设定身份认证决定的缓存时间。
默认时长为 2 分钟。配置文件使用 kubeconfig
文件的格式。文件中,clusters 指代远程服务,users 指代远程 API 服务
Webhook。下面是一个例子:
# Kubernetes API 版本
apiVersion : v1
# API 对象类别
kind : Config
# clusters 指代远程服务
clusters :
- name : name-of-remote-authn-service
cluster :
certificate-authority : /path/to/ca.pem # 用来验证远程服务的 CA
server : https://authn.example.com/authenticate # 要查询的远程服务 URL。必须使用 'https'。
# users 指代 API 服务的 Webhook 配置
users :
- name : name-of-api-server
user :
client-certificate : /path/to/cert.pem # Webhook 插件要使用的证书
client-key : /path/to/key.pem # 与证书匹配的密钥
# kubeconfig 文件需要一个上下文(Context),此上下文用于本 API 服务器
current-context : webhook
contexts :
- context :
cluster : name-of-remote-authn-service
user : name-of-api-sever
name : webhook
当客户端尝试在 API 服务器上使用持有者令牌完成身份认证(
如前 所述)时,
身份认证 Webhook 会用 POST 请求发送一个 JSON 序列化的对象到远程服务。
该对象是 authentication.k8s.io/v1beta1 组的 TokenReview 对象,
其中包含持有者令牌。
Kubernetes 不会强制请求提供此 HTTP 头部。
要注意的是,Webhook API 对象和其他 Kubernetes API 对象一样,也要受到同一
版本兼容规则 约束。
实现者要了解对 Beta 阶段对象的兼容性承诺,并检查请求的 apiVersion 字段,
以确保数据结构能够正常反序列化解析。此外,API 服务器必须启用
authentication.k8s.io/v1beta1 API 扩展组
(--runtime-config=authentication.k8s.io/v1beta1=true)。
POST 请求的 Body 部分将是如下格式:
{
"apiVersion" : "authentication.k8s.io/v1beta1" ,
"kind" : "TokenReview" ,
"spec" : {
"token" : "<持有者令牌>"
}
}
远程服务应该会填充请求的 status 字段,以标明登录操作是否成功。
响应的 Body 中的 spec 字段会被忽略,因此可以省略。
如果持有者令牌验证成功,应该返回如下所示的响应:
{
"apiVersion" : "authentication.k8s.io/v1beta1" ,
"kind" : "TokenReview" ,
"status" : {
"authenticated" : true ,
"user" : {
"username" : "janedoe@example.com" ,
"uid" : "42" ,
"groups" : [
"developers" ,
"qa"
],
"extra" : {
"extrafield1" : [
"extravalue1" ,
"extravalue2"
]
}
}
}
}
而不成功的请求会返回:
{
"apiVersion" : "authentication.k8s.io/v1beta1" ,
"kind" : "TokenReview" ,
"status" : {
"authenticated" : false
}
}
HTTP 状态码可用来提供进一步的错误语境信息。
身份认证代理 API 服务器可以配置成从请求的头部字段值(如 X-Remote-User)中辩识用户。
这一设计是用来与某身份认证代理一起使用 API 服务器,代理负责设置请求的头部字段值。
--requestheader-username-headers 必需字段,大小写不敏感。用来设置要获得用户身份所要检查的头部字段名称列表(有序)。第一个包含数值的字段会被用来提取用户名。--requestheader-group-headers 可选字段,在 Kubernetes 1.6 版本以后支持,大小写不敏感。
建议设置为 "X-Remote-Group"。用来指定一组头部字段名称列表,以供检查用户所属的组名称。
所找到的全部头部字段的取值都会被用作用户组名。--requestheader-extra-headers-prefix 可选字段,在 Kubernetes 1.6 版本以后支持,大小写不敏感。
建议设置为 "X-Remote-Extra-"。用来设置一个头部字段的前缀字符串,API 服务器会基于所给
前缀来查找与用户有关的一些额外信息。这些额外信息通常用于所配置的鉴权插件。
API 服务器会将与所给前缀匹配的头部字段过滤出来,去掉其前缀部分,将剩余部分
转换为小写字符串并在必要时执行百分号解码
后,构造新的附加信息字段键名。原来的头部字段值直接作为附加信息字段的值。例如,使用下面的配置:
--requestheader-username-headers=X-Remote-User
--requestheader-group-headers=X-Remote-Group
--requestheader-extra-headers-prefix=X-Remote-Extra-
针对所收到的如下请求:
GET / HTTP / 1.1
X-Remote-User: fido
X-Remote-Group: dogs
X-Remote-Group: dachshunds
X-Remote-Extra-Acme.com%2Fproject: some-project
X-Remote-Extra-Scopes: openid
X-Remote-Extra-Scopes: profile
会生成下面的用户信息:
name : fido
groups :
- dogs
- dachshunds
extra :
acme.com/project :
- some-project
scopes :
- openid
- profile
为了防范头部信息侦听,在请求中的头部字段被检视之前,
身份认证代理需要向 API 服务器提供一份合法的客户端证书,
供后者使用所给的 CA 来执行验证。
警告:不要 在不同的上下文中复用 CA 证书,除非你清楚这样做的风险是什么以及
应如何保护 CA 用法的机制。
--requestheader-client-ca-file 必需字段,给出 PEM 编码的证书包。
在检查请求的头部字段以提取用户名信息之前,必须提供一个合法的客户端证书,
且该证书要能够被所给文件中的机构所验证。--requestheader-allowed-names 可选字段,用来给出一组公共名称(CN)。
如果此标志被设置,则在检视请求中的头部以提取用户信息之前,必须提供
包含此列表中所给的 CN 名的、合法的客户端证书。匿名请求 启用匿名请求支持之后,如果请求没有被已配置的其他身份认证方法拒绝,则被视作
匿名请求(Anonymous Requests)。这类请求获得用户名 system:anonymous 和
对应的用户组 system:unauthenticated。
例如,在一个配置了令牌身份认证且启用了匿名访问的服务器上,如果请求提供了非法的
持有者令牌,则会返回 401 Unauthorized 错误。
如果请求没有提供持有者令牌,则被视为匿名请求。
在 1.5.1-1.5.x 版本中,匿名访问默认情况下是被禁用的,可以通过为 API 服务器设定
--anonymous-auth=true 来启用。
在 1.6 及之后版本中,如果所使用的鉴权模式不是 AlwaysAllow,则匿名访问默认是被启用的。
从 1.6 版本开始,ABAC 和 RBAC 鉴权模块要求对 system:anonymous 用户或者
system:unauthenticated 用户组执行显式的权限判定,所以之前的为 * 用户或
* 用户组赋予访问权限的策略规则都不再包含匿名用户。
用户伪装 一个用户可以通过伪装(Impersonation)头部字段来以另一个用户的身份执行操作。
使用这一能力,你可以手动重载请求被身份认证所识别出来的用户信息。
例如,管理员可以使用这一功能特性来临时伪装成另一个用户,查看请求是否被拒绝,
从而调试鉴权策略中的问题,
带伪装的请求首先会被身份认证识别为发出请求的用户,之后会切换到使用被伪装的用户
的用户信息。
用户发起 API 调用时 同时 提供自身的凭据和伪装头部字段信息 API 服务器对用户执行身份认证 API 服务器确认通过认证的用户具有伪装特权 请求用户的信息被替换成伪装字段的值 评估请求,鉴权组件针对所伪装的用户信息执行操作 以下 HTTP 头部字段可用来执行伪装请求:
Impersonate-User:要伪装成的用户名Impersonate-Group:要伪装成的用户组名。可以多次指定以设置多个用户组。
可选字段;要求 "Impersonate-User" 必须被设置。Impersonate-Extra-<附加名称>:一个动态的头部字段,用来设置与用户相关的附加字段。
此字段可选;要求 "Impersonate-User" 被设置。为了能够以一致的形式保留,
<附加名称>部分必须是小写字符,如果有任何字符不是
合法的 HTTP 头部标签字符 ,
则必须是 utf8 字符,且转换为百分号编码 。说明: 在 1.11.3 版本之前(以及 1.10.7、1.9.11),<附加名称> 只能包含
合法的 HTTP 标签字符。
头部字段集合的示例:
Impersonate-User: jane.doe@example.com
Impersonate-Group: developers
Impersonate-Group: admins
Impersonate-Extra-dn: cn=jane,ou=engineers,dc=example,dc=com
Impersonate-Extra-acme.com%2Fproject: some-project
Impersonate-Extra-scopes: view
Impersonate-Extra-scopes: development
在使用 kubectl 时,可以使用 --as 标志来配置 Impersonate-User 头部字段值,
使用 --as-group 标志配置 Impersonate-Group 头部字段值。
Error from server (Forbidden): User "clark" cannot get nodes at the cluster scope. (get nodes mynode)
设置 --as 和 --as-group 标志:
kubectl drain mynode --as= superman --as-group= system:masters
node/mynode cordoned
node/mynode drained
要伪装成某个用户、某个组或者设置附加字段,执行伪装操作的用户必须具有对所伪装的
类别(“user”、“group” 等)执行 “impersonate” 动词操作的能力。
对于启用了 RBAC 鉴权插件的集群,下面的 ClusterRole 封装了设置用户和组伪装字段
所需的规则:
apiVersion : rbac.authorization.k8s.io/v1
kind : ClusterRole
metadata :
name : impersonator
rules :
- apiGroups : ["" ]
resources : ["users" , "groups" , "serviceaccounts" ]
verbs : ["impersonate" ]
附加字段会被作为 userextras 资源的子资源来执行权限评估。
如果要允许用户为附加字段 “scopes” 设置伪装头部,该用户需要被授予以下规则:
apiVersion : rbac.authorization.k8s.io/v1
kind : ClusterRole
metadata :
name : scopes-impersonator
rules :
# 可以设置 "Impersonate-Extra-scopes" 头部
- apiGroups : ["authentication.k8s.io" ]
resources : ["userextras/scopes" ]
verbs : ["impersonate" ]
你也可以通过约束资源可能对应的 resourceNames 限制伪装头部的取值:
apiVersion : rbac.authorization.k8s.io/v1
kind : ClusterRole
metadata :
name : limited-impersonator
rules :
# 可以伪装成用户 "jane.doe@example.com"
- apiGroups : ["" ]
resources : ["users" ]
verbs : ["impersonate" ]
resourceNames : ["jane.doe@example.com" ]
# 可以伪装成用户组 "developers" 和 "admins"
- apiGroups : ["" ]
resources : ["groups" ]
verbs : ["impersonate" ]
resourceNames : ["developers" ,"admins" ]
# 可以将附加字段 "scopes" 伪装成 "view" 和 "development"
- apiGroups : ["authentication.k8s.io" ]
resources : ["userextras/scopes" ]
verbs : ["impersonate" ]
resourceNames : ["view" , "development" ]
client-go 凭据插件 FEATURE STATE: Kubernetes v1.11 [beta]
k8s.io/client-go 及使用它的工具(如 kubectl 和 kubelet)可以执行某个外部
命令来获得用户的凭据信息。
这一特性的目的是便于客户端与 k8s.io/client-go 并不支持的身份认证协议(LDAP、
Kerberos、OAuth2、SAML 等)继承。
插件实现特定于协议的逻辑,之后返回不透明的凭据以供使用。
几乎所有的凭据插件使用场景中都需要在服务器端存在一个支持
Webhook 令牌身份认证组件 的模块,
负责解析客户端插件所生成的凭据格式。
示例应用场景 在一个假想的应用场景中,某组织运行这一个外部的服务,能够将特定用户的已签名的
令牌转换成 LDAP 凭据。此服务还能够对
Webhook 令牌身份认证组件 的请求做出响应以
验证所提供的令牌。用户需要在自己的工作站上安装一个凭据插件。
要对 API 服务器认证身份时:
用户发出 kubectl 命令。 凭据插件提示用户输入 LDAP 凭据,并与外部服务交互,获得令牌。 凭据插件将令牌返回该 client-go,后者将其用作持有者令牌提交给 API 服务器。 API 服务器使用Webhook 令牌身份认证组件 向
外部服务发出 TokenReview 请求。 外部服务检查令牌上的签名,返回用户的用户名和用户组信息。 配置 凭据插件通过 kubectl 配置文件
来作为 user 字段的一部分设置。
apiVersion : v1
kind : Config
users :
- name : my-user
user :
exec :
# 要执行的命令。必需。
command : "example-client-go-exec-plugin"
# 解析 ExecCredentials 资源时使用的 API 版本。必需。
#
# 插件返回的 API 版本必需与这里列出的版本匹配。
#
# 要与支持多个版本的工具(如 client.authentication.k8sio/v1alpha1)集成,
# 可以设置一个环境变量或者向工具传递一个参数标明 exec 插件所期望的版本。
apiVersion : "client.authentication.k8s.io/v1beta1"
# 执行此插件时要设置的环境变量。可选字段。
env :
- name : "FOO"
value : "bar"
# 执行插件时要传递的参数。可选字段。
args :
- "arg1"
- "arg2"
# 当可执行文件不存在时显示给用户的文本。可选的。
installHint : |
需要 example-client-go-exec-plugin 来在当前集群上执行身份认证。可以通过以下命令安装:
MacOS: brew install example-client-go-exec-plugin
Ubuntu: apt-get install example-client-go-exec-plugin
Fedora: dnf install example-client-go-exec-plugin
...
# 是否使用 KUBERNETES_EXEC_INFO 环境变量的一部分向这个 exec 插件
# 提供集群信息(可能包含非常大的 CA 数据)
provideClusterInfo : true
clusters :
- name : my-cluster
cluster :
server : "https://172.17.4.100:6443"
certificate-authority : "/etc/kubernetes/ca.pem"
extensions :
- name : client.authentication.k8s.io/exec # 为每个集群 exec 配置保留的扩展名
extension :
arbitrary : config
this : 在设置 provideClusterInfo 时可通过环境变量 KUBERNETES_EXEC_INFO 指定
you : ["can" , "put" , "anything" , "here" ]
contexts :
- name : my-cluster
context :
cluster : my-cluster
user : my-user
current-context : my-cluster
解析相对命令路径时,kubectl 将其视为与配置文件比较而言的相对路径。
如果 KUBECONFIG 被设置为 /home/jane/kubeconfig,而 exec 命令为
./bin/example-client-go-exec-plugin,则要执行的可执行文件为
/home/jane/bin/example-client-go-exec-plugin。
- name : my-user
user :
exec :
# 对 kubeconfig 目录而言的相对路径
command : "./bin/example-client-go-exec-plugin"
apiVersion : "client.authentication.k8s.io/v1beta1"
所执行的命令会在 stdout 打印 ExecCredential 对象。
k8s.io/client-go 使用 status 中返回的凭据信息向 Kubernetes API 服务器
执行身份认证。
在交互式会话中运行时,stdin 是直接暴露给插件使用的。
插件应该使用
TTY check
来确定是否适合用交互方式请求用户输入。
与使用持有者令牌凭据,插件在 ExecCredential 的状态中返回一个令牌:
{
"apiVersion" : "client.authentication.k8s.io/v1beta1" ,
"kind" : "ExecCredential" ,
"status" : {
"token" : "my-bearer-token"
}
}
另一种方案是,返回 PEM 编码的客户端证书和密钥,以便执行 TLS 客户端身份认证。
如果插件在后续调用中返回了不同的证书或密钥,k8s.io/client-go
会终止其与服务器的连接,从而强制执行新的 TLS 握手过程。
如果指定了这种方式,则 clientKeyData 和 clientCertificateData 字段都必需存在。
clientCertificateData 字段可能包含一些要发送给服务器的中间证书(Intermediate
Certificates)。
{
"apiVersion" : "client.authentication.k8s.io/v1beta1" ,
"kind" : "ExecCredential" ,
"status" : {
"clientCertificateData" : "-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----" ,
"clientKeyData" : "-----BEGIN RSA PRIVATE KEY-----\n...\n-----END RSA PRIVATE KEY-----"
}
}
作为一种可选方案,响应中还可以包含以 RFC3339 时间戳格式给出的证书到期时间。
证书到期时间的有无会有如下影响:
如果响应中包含了到期时间,持有者令牌和 TLS 凭据会被缓存,直到到期期限到来、
或者服务器返回 401 HTTP 状态码,或者进程退出。 如果未指定到期时间,则持有者令牌和 TLS 凭据会被缓存,直到服务器返回 401
HTTP 状态码或者进程退出。 {
"apiVersion" : "client.authentication.k8s.io/v1beta1" ,
"kind" : "ExecCredential" ,
"status" : {
"token" : "my-bearer-token" ,
"expirationTimestamp" : "2018-03-05T17:30:20-08:00"
}
}
调用此插件时可以选择性地设置环境变量 KUBERNETES_EXEC_INFO。
该变量包含了此插件获取凭据所针对的集群信息。此信息可用于执行群集特定的凭据获取逻辑。
为了启用此行为,必须在 kubeconfig
中的 exec user 字段上设置provideClusterInfo字段。
下面是上述 KUBERNETES_EXEC_INFO 环境变量的示例。
{
"apiVersion" : "client.authentication.k8s.io/v1beta1" ,
"kind" : "ExecCredential" ,
"spec" : {
"cluster" : {
"server" : "https://172.17.4.100:6443" ,
"certificate-authority-data" : "LS0t..." ,
"config" : {
"arbitrary" : "config" ,
"this" : "在设置 provideClusterInfo 时可通过环境变量 KUBERNETES_EXEC_INFO 指定" ,
"you" : ["can" , "put" , "anything" , "here" ]
}
}
}
}
6.5.2 - 使用启动引导令牌(Bootstrap Tokens)认证 FEATURE STATE: Kubernetes v1.18 [stable]
启动引导令牌是一种简单的持有者令牌(Bearer Token),这种令牌是在新建集群
或者在现有集群中添加新节点时使用的。
它被设计成能够支持 kubeadm ,
但是也可以被用在其他的案例中以便用户在不使用 kubeadm 的情况下启动集群。
它也被设计成可以通过 RBAC 策略,结合
Kubelet TLS 启动引导
系统进行工作。
启动引导令牌被定义成一个特定类型的 Secret(bootstrap.kubernetes.io/token),
并存在于 kube-system 名字空间中。
这些 Secret 会被 API 服务器上的启动引导认证组件(Bootstrap Authenticator)读取。
控制器管理器中的控制器 TokenCleaner 能够删除过期的令牌。
这些令牌也被用来在节点发现的过程中会使用的一个特殊的 ConfigMap 对象。
BootstrapSigner 控制器也会使用这一 ConfigMap。
令牌格式 启动引导令牌使用 abcdef.0123456789abcdef 的形式。
更加规范地说,它们必须符合正则表达式 [a-z0-9]{6}\.[a-z0-9]{16}。
令牌的第一部分是 “Token ID”,它是一种公开信息,用于引用令牌并确保不会
泄露认证所使用的秘密信息。
第二部分是“令牌秘密(Token Secret)”,它应该被共享给受信的第三方。
启用启动引导令牌 启用启动引导令牌身份认证 启动引导令牌认证组件可以通过 API 服务器上的如下标志启用:
--enable-bootstrap-token-auth
启动引导令牌被启用后,可以作为持有者令牌的凭据,用于 API 服务器请求的身份认证。
Authorization: Bearer 07401b.f395accd246ae52d
令牌认证为用户名 system:bootstrap:<token id> 并且是组 system:bootstrappers
的成员。额外的组信息可以通过令牌的 Secret 来设置。
过期的令牌可以通过启用控制器管理器中的 tokencleaner 控制器来删除。
每个合法的令牌背后对应着 kube-system 名字空间中的某个 Secret 对象。
你可以从
这里 .
找到完整设计文档。
这是 Secret 看起来的样子。
apiVersion : v1
kind : Secret
metadata :
# name 必须是 "bootstrap-token-<token id>" 格式的
name : bootstrap-token-07401b
namespace : kube-system
# type 必须是 'bootstrap.kubernetes.io/token'
type : bootstrap.kubernetes.io/token
stringData :
# 供人阅读的描述,可选。
description : "The default bootstrap token generated by 'kubeadm init'."
# 令牌 ID 和秘密信息,必需。
token-id : 07401b
token-secret : base64(f395accd246ae52d)
# 可选的过期时间字段
expiration : "2017-03-10T03:22:11Z"
# 允许的用法
usage-bootstrap-authentication : "true"
usage-bootstrap-signing : "true"
# 令牌要认证为的额外组,必须以 "system:bootstrappers:" 开头
auth-extra-groups : system:bootstrappers:worker,system:bootstrappers:ingress
Secret 的类型必须是 bootstrap.kubernetes.io/token,而且名字必须是 bootstrap-token-<token id>。
令牌必须存在于 kube-system 名字空间中。
usage-bootstrap-* 成员表明这个 Secret 的用途。启用时,值必须设置为 true。
usage-bootstrap-authentication 表示令牌可以作为持有者令牌用于 API 服务器的身份认证。usage-bootstrap-signing 表示令牌可被用于 cluster-info ConfigMap 的签名,
就像下面描述的那样。expiration 字段控制令牌的失效期。过期的令牌在用于身份认证时会被拒绝,在用于
ConfigMap 签名时会被忽略。
过期时间值是遵循 RFC3339 进行编码的 UTC 时间。
启用 TokenCleaner 控制器会自动删除过期的令牌。
使用 kubeadm 管理令牌 你可以使用 kubeadm 工具管理运行中集群上的令牌。
参见 kubeadm token 文档
以了解详细信息。
ConfigMap 签名 除了身份认证,令牌还可以用于签名 ConfigMap。
这一用法发生在集群启动过程的早期,在客户端信任 API 服务器之前。
被签名的 ConfigMap 可以被共享令牌完成身份认证。
通过在控制器管理器上启用 bootstrapsigner 控制器可以启用 ConfigMap 签名特性。
--controllers=*,bootstrapsigner
被签名的 ConfigMap 是 kube-public 名字空间中的 cluster-info。
典型的工作流中,客户端在未经认证和忽略 TLS 报错的状态下读取这个 ConfigMap。
通过检查 ConfigMap 中嵌入的签名校验 ConfigMap 的载荷。
ConfigMap 会是这个样子的:
apiVersion : v1
kind : ConfigMap
metadata :
name : cluster-info
namespace : kube-public
data :
jws-kubeconfig-07401b : eyJhbGciOiJIUzI1NiIsImtpZCI6IjA3NDAxYiJ9..tYEfbo6zDNo40MQE07aZcQX2m3EB2rO3NuXtxVMYm9U
kubeconfig : |
apiVersion: v1
clusters:
- cluster:
certificate-authority-data: <非常长的证书数据>
server: https://10.138.0.2:6443
name: ""
contexts: []
current-context: ""
kind: Config
preferences: {}
users: []
ConfigMap 的 kubeconfig 成员是一个填好了集群信息的配置文件。
这里主要交换的信息是 certificate-authority-data。在将来可能会有扩展。
签名是一个使用 “detached” 模式生成的 JWS 签名。
为了检验签名,用户应该按照 JWS 规则(base64 编码且丢掉结尾的 =)对
kubeconfig 的载荷进行编码。完成编码的载荷会被插入到两个句点中间,形成完整的
JWS。你可以使用完整的令牌(比如 07401b.f395accd246ae52d)作为共享密钥,
通过 HS256 方式 (HMAC-SHA256) 对 JWS 进行校验。
用户 必须 确保使用了 HS256。
警告: 任何拥有了启动引导令牌的主体都可以为该令牌生成一个合法的签名。
当使用 ConfigMap 签名时,非常不建议针对很多客户使用相同的令牌,因为某个被攻击的
客户可能对另一个一来签名来开启 TLS 信任的客户发起中间人攻击。
参考 kubeadm 实现细节
了解更多信息。
6.5.3 - 证书签名请求 FEATURE STATE: Kubernetes v1.19 [stable]
证书 API 支持
X.509
的自动化配置,
它为 Kubernetes API 的客户端提供一个编程接口,
用于从证书颁发机构(CA)请求并获取 X.509
证书 。
CertificateSigningRequest(CSR)资源用来向指定的签名者申请证书签名,
在最终签名之前,申请可能被批准,也可能被拒绝。
请求签名流程 CertificateSigningRequest 资源类型允许客户使用它申请发放 X.509 证书。
CertificateSigningRequest 对象 在 spec.request 中包含一个 PEM 编码的 PKCS#10 签名请求。
CertificateSigningRequest 使用 spec.signerName 字段标示 签名者 (请求的接收方)。
注意,spec.signerName 在 certificates.k8s.io/v1 之后的 API 版本是必填项。
创建完成的 CertificateSigningRequest,要先通过批准,然后才能签名。
根据所选的签名者,CertificateSigningRequest 可能会被
控制器 自动批准。
否则,就必须人工批准,
人工批准可以使用 REST API(或 go 客户端),也可以执行 kubectl certificate approve 命令。
同样,CertificateSigningRequest 也可能被驳回,
这就相当于通知了指定的签名者,这个证书不能签名。
对于已批准的证书,下一步是签名。
对应的签名控制器首先验证签名条件是否满足,然后才创建证书。
签名控制器然后更新 CertificateSigningRequest,
将新证书保存到现有 CertificateSigningRequest 对象的 status.certificate 字段中。
此时,字段 status.certificate 要么为空,要么包含一个用 PEM 编码的 X.509 证书。
直到签名完成前,CertificateSigningRequest 的字段 status.certificate 都为空。
一旦 status.certificate 字段完成填充,请求既算完成,
客户端现在可以从 CertificateSigningRequest 资源中获取已签名的证书的 PEM 数据。
当然如果不满足签名条件,签名者可以拒签。
为了减少集群中遗留的过时的 CertificateSigningRequest 资源的数量,
一个垃圾收集控制器将会周期性地运行。
此垃圾收集器会清除在一段时间内没有改变过状态的 CertificateSigningRequests:
已批准的请求:1小时后自动删除 已拒绝的请求:1小时后自动删除 挂起的请求:1小时后自动删除 签名者 所有签名者都应该提供自己工作方式的信息,
以便客户端可以预期到他们的 CSR 将发生什么。
此类信息包括:
信任分发 :信任(CA 证书包)是如何分发的。许可的主体 :当一个受限制的主体(subject)发送请求时,相应的限制和应对手段。许可的 x509 扩展 :包括 IP subjectAltNames、DNS subjectAltNames、
Email subjectAltNames、URI subjectAltNames 等,请求一个受限制的扩展项时的应对手段。许可的密钥用途/扩展的密钥用途 :当用途和签名者在 CSR 中指定的用途不同时,
相应的限制和应对手段。过期时间/证书有效期 :过期时间由签名者确定、由管理员配置,还是由 CSR 对象指定等,
以及过期时间与签名者在 CSR 中指定过期时间不同时的应对手段。允许/不允许 CA 位 :当 CSR 包含一个签名者并不允许的 CA 证书的请求时,相应的应对手段。一般来说,当 CSR 被批准通过,且证书被签名后,status.certificate 字段
将包含一个 PEM 编码的 X.509 证书。
有些签名者在 status.certificate 字段中存储多个证书。
在这种情况下,签名者的说明文档应当指明附加证书的含义。
例如,这是要在 TLS 握手时提供的证书和中继证书。
PKCS#10 签名请求格式不允许设置证书的过期时间或者生命期。因此,证书的过期
时间或者生命期必须通过类似 CSR 对象的注解字段这种形式来设置。
尽管让签名者使用过期日期从理论上来讲也是可行的,目前还不存在哪个实现这样做了。
(内置的签名者都是用相同的 ClusterSigningDuration 配置选项,而该选项
中将生命期的默认值设为 1 年,且可通过 kube-controller-manager 的命令行选项
--cluster-signing-duration 来更改。)
Kubernetes 签名者 Kubernetes提供了内置的签名者,每个签名者都有一个众所周知的 signerName:
kubernetes.io/kube-apiserver-client:签名的证书将被 API 服务器视为客户证书。
kube-controller-manager 不会自动批准它。信任分发:签名的证书将被 API 服务器视为客户端证书。CA 证书包不通过任何其他方式分发。 许可的主体:没有主体限制,但审核人和签名者可以选择不批准或不签署。
某些主体,比如集群管理员级别的用户或组因部署和安装方式不同而不同,
所以批准和签署之前需要进行额外仔细审查。
用来限制 system:masters 的 CertificateSubjectRestriction 准入插件默认处于启用状态,
但它通常不是集群中唯一的集群管理员主体。 许可的 x509 扩展:允许 subjectAltName 和 key usage 扩展,弃用其他扩展。 许可的密钥用途:必须包含 ["client auth"],但不能包含
["digital signature", "key encipherment", "client auth"] 之外的键。 过期时间/证书有效期:通过 kube-controller-manager 中 --cluster-signing-duration
标志来设置,由其中的签名者实施。 允许/不允许 CA 位:不允许。 kubernetes.io/kube-apiserver-client-kubelet: 签名的证书将被 kube-apiserver 视为客户证书。
kube-controller-manager 可以自动批准它。
信任分发:签名的证书将被 API 服务器视为客户端证书。CA 证书包不通过任何其他方式分发。 许可的主体:组织名必须是 ["system:nodes"],用户名以 "system:node:" 开头 许可的 x509 扩展:允许 key usage 扩展,禁用 subjectAltName 扩展,并删除其他扩展。 许可的密钥用途:必须是 ["key encipherment", "digital signature", "client auth"] 过期时间/证书有效期:通过 kube-controller-manager 中签名者的实现所对应的标志
--cluster-signing-duration 来设置。 允许/不允许 CA 位:不允许。 kubernetes.io/kubelet-serving: 签名服务证书,该服务证书被 API 服务器视为有效的 kubelet 服务证书,
但没有其他保证。kube-controller-manager 不会自动批准它。信任分发:签名的证书必须被 kube-apiserver 认可,可有效的中止 kubelet 连接。CA 证书包不通过任何其他方式分发。 许可的主体:组织名必须是 ["system:nodes"],用户名以 "system:node:" 开头 许可的 x509 扩展:允许 key usage、DNSName/IPAddress subjectAltName 等扩展,
禁止 EmailAddress、URI subjectAltName 等扩展,并丢弃其他扩展。
至少有一个 DNS 或 IP 的 SubjectAltName 存在。 许可的密钥用途:必须是 ["key encipherment", "digital signature", "client auth"] 过期日期/证书生命期:通过 kube-controller-manager 中签名者的实现所对应的标志
--cluster-signing-duration 来设置。 允许/不允许 CA 位:不允许。 kubernetes.io/legacy-unknown: 不保证信任。Kubernetes 的一些第三方发行版可能会使用它签署的客户端证书。
稳定版的 CertificateSigningRequest API(certificates.k8s.io/v1 以及之后的版本)不允许将
signerName 设置为 kubernetes.io/legacy-unknown。
kube-controller-manager 不会自动批准这类请求。信任分发:没有。这个签名者在 Kubernetes 集群中没有标准的信任或分发。 许可的主体:全部。 许可的 x509 扩展:允许 subjectAltName 和 key usage 等扩展,并弃用其他扩展。 许可的密钥用途:全部。 过期日期/证书生命期:通过 kube-controller-manager 中签名者的实现所对应的标志
--cluster-signing-duration 来设置。 允许/不允许 CA 位 - 不允许。 说明: 注意:所有这些故障仅在 kube-controller-manager 日志中报告。
对于这些签名者,信任的分发发生在带外(out of band)。上述信任之外的任何信任都是完全巧合的。
例如,一些发行版可能会将 kubernetes.io/legacy-unknown 作为 kube-apiserver 的客户端证书,
但这个做法并不标准。
这些用途都没有以任何方式涉及到 ServiceAccount 中的 Secrets .data[ca.crt]。
此 CA 证书包只保证使用默认的服务(kubernetes.default.svc)来验证到 API 服务器的连接。
鉴权 授权创建 CertificateSigningRequest 和检索 CertificateSigningRequest:
verbs(动词): create、get、list、watch,
group(组):certificates.k8s.io,
resources:certificatesigningrequests 例如:
apiVersion : rbac.authorization.k8s.io/v1
kind : ClusterRole
metadata :
name : csr-creator
rules :
- apiGroups :
- certificates.k8s.io
resources :
- certificatesigningrequests
verbs :
- create
- get
- list
- watch
授权批准 CertificateSigningRequest:
verbs(动词): get、list、watch,
group(组):certificates.k8s.io,
resources(资源):certificatesigningrequests verbs(动词): update,
group(组):certificates.k8s.io,
resources(资源):certificatesigningrequests/approval verbs(动词):approve,
group(组):certificates.k8s.io,
resources(资源):signers,
resourceName:<signerNameDomain>/<signerNamePath> 或 <signerNameDomain>/* 例如:
apiVersion : rbac.authorization.k8s.io/v1
kind : ClusterRole
metadata :
name : csr-approver
rules :
- apiGroups :
- certificates.k8s.io
resources :
- certificatesigningrequests
verbs :
- get
- list
- watch
- apiGroups :
- certificates.k8s.io
resources :
- certificatesigningrequests/approval
verbs :
- update
- apiGroups :
- certificates.k8s.io
resources :
- signers
resourceNames :
- example.com/my-signer-name # example.com/* can be used to authorize for all signers in the 'example.com' domain
verbs :
- approve
授权签名 CertificateSigningRequest:
verbs(动词):get、list、watch,
group(组):certificates.k8s.io,
resources(资源):certificatesigningrequests verbs(动词):update,
group(组):certificates.k8s.io,
resources(资源):certificatesigningrequests/status verbs(动词):sign,
group(组):certificates.k8s.io,
resources(资源):signers,
resourceName:<signerNameDomain>/<signerNamePath> 或 <signerNameDomain>/* apiVersion : rbac.authorization.k8s.io/v1
kind : ClusterRole
metadata :
name : csr-signer
rules :
- apiGroups :
- certificates.k8s.io
resources :
- certificatesigningrequests
verbs :
- get
- list
- watch
- apiGroups :
- certificates.k8s.io
resources :
- certificatesigningrequests/status
verbs :
- update
- apiGroups :
- certificates.k8s.io
resources :
- signers
resourceNames :
- example.com/my-signer-name # example.com/* can be used to authorize for all signers in the 'example.com' domain
verbs :
- sign
普通用户 为了让普通用户能够通过认证并调用 API,需要执行几个步骤。
首先,该用户必须拥有 Kubernetes 集群签发的证书,
然后将该证书作为 API 调用的 Certificate 头或通过 kubectl 提供。
创建私钥 下面的脚本展示了如何生成 PKI 私钥和 CSR。
设置 CSR 的 CN 和 O 属性很重要。CN 是用户名,O 是该用户归属的组。
你可以参考 RBAC 了解标准组的信息。
openssl genrsa -out john.key 2048
openssl req -new -key john.key -out john.csr
创建 CertificateSigningRequest 创建一个 CertificateSigningRequest,并通过 kubectl 将其提交到 Kubernetes 集群。
下面是生成 CertificateSigningRequest 的脚本。
cat <<EOF | kubectl apply -f -
apiVersion: certificates.k8s.io/v1
kind: CertificateSigningRequest
metadata:
name: john
spec:
groups:
- system:authenticated
request: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURSBSRVFVRVNULS0tLS0KTUlJQ1ZqQ0NBVDRDQVFBd0VURVBNQTBHQTFVRUF3d0dZVzVuWld4aE1JSUJJakFOQmdrcWhraUc5dzBCQVFFRgpBQU9DQVE4QU1JSUJDZ0tDQVFFQTByczhJTHRHdTYxakx2dHhWTTJSVlRWMDNHWlJTWWw0dWluVWo4RElaWjBOCnR2MUZtRVFSd3VoaUZsOFEzcWl0Qm0wMUFSMkNJVXBGd2ZzSjZ4MXF3ckJzVkhZbGlBNVhwRVpZM3ExcGswSDQKM3Z3aGJlK1o2MVNrVHF5SVBYUUwrTWM5T1Nsbm0xb0R2N0NtSkZNMUlMRVI3QTVGZnZKOEdFRjJ6dHBoaUlFMwpub1dtdHNZb3JuT2wzc2lHQ2ZGZzR4Zmd4eW8ybmlneFNVekl1bXNnVm9PM2ttT0x1RVF6cXpkakJ3TFJXbWlECklmMXBMWnoyalVnald4UkhCM1gyWnVVV1d1T09PZnpXM01LaE8ybHEvZi9DdS8wYk83c0x0MCt3U2ZMSU91TFcKcW90blZtRmxMMytqTy82WDNDKzBERHk5aUtwbXJjVDBnWGZLemE1dHJRSURBUUFCb0FBd0RRWUpLb1pJaHZjTgpBUUVMQlFBRGdnRUJBR05WdmVIOGR4ZzNvK21VeVRkbmFjVmQ1N24zSkExdnZEU1JWREkyQTZ1eXN3ZFp1L1BVCkkwZXpZWFV0RVNnSk1IRmQycVVNMjNuNVJsSXJ3R0xuUXFISUh5VStWWHhsdnZsRnpNOVpEWllSTmU3QlJvYXgKQVlEdUI5STZXT3FYbkFvczFqRmxNUG5NbFpqdU5kSGxpT1BjTU1oNndLaTZzZFhpVStHYTJ2RUVLY01jSVUyRgpvU2djUWdMYTk0aEpacGk3ZnNMdm1OQUxoT045UHdNMGM1dVJVejV4T0dGMUtCbWRSeEgvbUNOS2JKYjFRQm1HCkkwYitEUEdaTktXTU0xMzhIQXdoV0tkNjVoVHdYOWl4V3ZHMkh4TG1WQzg0L1BHT0tWQW9FNkpsYWFHdTlQVmkKdjlOSjVaZlZrcXdCd0hKbzZXdk9xVlA3SVFjZmg3d0drWm89Ci0tLS0tRU5EIENFUlRJRklDQVRFIFJFUVVFU1QtLS0tLQo=
signerName: kubernetes.io/kube-apiserver-client
usages:
- client auth
EOF
需要注意的几点:
usage 字段必须是 'client auth'request 字段是 CSR 文件内容的 base64 编码值。
要得到该值,可以执行命令 cat john.csr | base64 | tr -d "\n"。批准证书签名请求 使用 kubectl 创建 CSR 并批准。
获取 CSR 列表:
批准 CSR:
kubectl certificate approve john
取得证书 从 CSR 取得证书:
kubectl get csr/john -o yaml
证书的内容使用 base64 编码,存放在字段 status.certificate。
创建角色和角色绑定 创建了证书之后,为了让这个用户能访问 Kubernetes 集群资源,现在就要创建
Role 和 RoleBinding 了。
下面是为这个新用户创建 Role 的示例脚本:
kubectl create role developer --verb= create --verb= get --verb= list --verb= update --verb= delete --resource= pods
下面是为这个新用户创建 RoleBinding 的示例命令:
kubectl create rolebinding developer-binding-john --role= developer --user= john
添加到 kubeconfig 最后一步是将这个用户添加到 kubeconfig 文件。
我们假设私钥和证书文件存放在 “/home/vagrant/work/” 目录中。
首先,我们需要添加新的凭据:
kubectl config set-credentials john --client-key= /home/vagrant/work/john.key --client-certificate= /home/vagrant/work/john.crt --embed-certs= true
然后,你需要添加上下文:
kubectl config set-context john --cluster= kubernetes --user= john
来测试一下,把上下文切换为 john:
kubectl config use-context john
批准和驳回 控制平面的自动化批准 kube-controller-manager 内建了一个证书批准者,其 signerName 为
kubernetes.io/kube-apiserver-client-kubelet,
该批准者将 CSR 上用于节点凭据的各种权限委托给权威认证机构。
kube-controller-manager 将 SubjectAccessReview 资源发送(POST)到 API 服务器,
以便检验批准证书的授权。
使用 kubectl 批准或驳回 Kubernetes 管理员(拥有足够的权限)可以手工批准(或驳回)CertificateSigningRequests,
此操作使用 kubectl certificate approve 和 kubectl certificate deny 命令实现。
使用 kubectl 批准一个 CSR:
kubectl certificate approve <certificate-signing-request-name>
同样地,驳回一个 CSR:
kubectl certificate deny <certificate-signing-request-name>
使用 Kubernetes API 批准或驳回 REST API 的用户可以通过向待批准的 CSR 的 approval 子资源提交更新请求来批准 CSR。
例如,你可以编写一个
operator
来监视特定类型的 CSR,然后发送一个更新来批准它。
当你发出批准或驳回的指令时,根据你期望的状态来选择设置 Approved 或 Denied。
批准(Approved) 的 CSR:
apiVersion : certificates.k8s.io/v1
kind : CertificateSigningRequest
...
status :
conditions :
- lastUpdateTime : "2020-02-08T11:37:35Z"
lastTransitionTime : "2020-02-08T11:37:35Z"
message : Approved by my custom approver controller
reason : ApprovedByMyPolicy # You can set this to any string
type : Approved
驳回(Denied)的 CRS:
apiVersion : certificates.k8s.io/v1
kind : CertificateSigningRequest
...
status :
conditions :
- lastUpdateTime : "2020-02-08T11:37:35Z"
lastTransitionTime : "2020-02-08T11:37:35Z"
message : Denied by my custom approver controller
reason : DeniedByMyPolicy # You can set this to any string
type : Denied
status.conditions.reason 字段通常设置为一个首字母大写的对机器友好的原因码;
这是一个命名约定,但你也可以随你的个人喜好设置。
如果你想添加一个仅供人类使用的注释,那就用 status.conditions.message 字段。
签名 控制平面签名者 Kubernetes 控制平面实现了每一个
Kubernetes 签名者 ,
每个签名者的实现都是 kube-controller-manager 的一部分。
说明: 在Kubernetes v1.18 之前,
kube-controller-manager 签名所有标记为 approved 的 CSR。
基于 API 的签名者 REST API 的用户可以通过向待签名的 CSR 的 status 子资源提交更新请求来对 CSR 进行签名。
作为这个请求的一部分, status.certificate 字段应设置为已签名的证书。
此字段可包含一个或多个 PEM 编码的证书。
所有的 PEM 块必须具备 "CERTIFICATE" 标签,且不包含文件头,且编码的数据必须是
RFC5280 第 4 节
中描述的 BER 编码的 ASN.1 证书结构。
-----BEGIN CERTIFICATE-----
MIIDgjCCAmqgAwIBAgIUC1N1EJ4Qnsd322BhDPRwmg3b/oAwDQYJKoZIhvcNAQEL
BQAwXDELMAkGA1UEBhMCeHgxCjAIBgNVBAgMAXgxCjAIBgNVBAcMAXgxCjAIBgNV
BAoMAXgxCjAIBgNVBAsMAXgxCzAJBgNVBAMMAmNhMRAwDgYJKoZIhvcNAQkBFgF4
MB4XDTIwMDcwNjIyMDcwMFoXDTI1MDcwNTIyMDcwMFowNzEVMBMGA1UEChMMc3lz
dGVtOm5vZGVzMR4wHAYDVQQDExVzeXN0ZW06bm9kZToxMjcuMC4wLjEwggEiMA0G
CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDne5X2eQ1JcLZkKvhzCR4Hxl9+ZmU3
+e1zfOywLdoQxrPi+o4hVsUH3q0y52BMa7u1yehHDRSaq9u62cmi5ekgXhXHzGmm
kmW5n0itRECv3SFsSm2DSghRKf0mm6iTYHWDHzUXKdm9lPPWoSOxoR5oqOsm3JEh
Q7Et13wrvTJqBMJo1GTwQuF+HYOku0NF/DLqbZIcpI08yQKyrBgYz2uO51/oNp8a
sTCsV4OUfyHhx2BBLUo4g4SptHFySTBwlpRWBnSjZPOhmN74JcpTLB4J5f4iEeA7
2QytZfADckG4wVkhH3C2EJUmRtFIBVirwDn39GXkSGlnvnMgF3uLZ6zNAgMBAAGj
YTBfMA4GA1UdDwEB/wQEAwIFoDATBgNVHSUEDDAKBggrBgEFBQcDAjAMBgNVHRMB
Af8EAjAAMB0GA1UdDgQWBBTREl2hW54lkQBDeVCcd2f2VSlB1DALBgNVHREEBDAC
ggAwDQYJKoZIhvcNAQELBQADggEBABpZjuIKTq8pCaX8dMEGPWtAykgLsTcD2jYr
L0/TCrqmuaaliUa42jQTt2OVsVP/L8ofFunj/KjpQU0bvKJPLMRKtmxbhXuQCQi1
qCRkp8o93mHvEz3mTUN+D1cfQ2fpsBENLnpS0F4G/JyY2Vrh19/X8+mImMEK5eOy
o0BMby7byUj98WmcUvNCiXbC6F45QTmkwEhMqWns0JZQY+/XeDhEcg+lJvz9Eyo2
aGgPsye1o3DpyXnyfJWAWMhOz7cikS5X2adesbgI86PhEHBXPIJ1v13ZdfCExmdd
M1fLPhLyR54fGaY+7/X8P9AZzPefAkwizeXwe9ii6/a08vWoiE4=
-----END CERTIFICATE-----
非 PEM 内容可能会出现在证书 PEM 块前后的位置,且未经验证,
以允许使用 RFC7468 第5.2节 中描述的解释性文本。
当使用 JSON 或 YAML 格式时,此字段是 base-64 编码。
包含上述示例证书的 CertificateSigningRequest 如下所示:
apiVersion : certificates.k8s.io/v1
kind : CertificateSigningRequest
...
status :
certificate : "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JS..."
接下来 6.5.4 - 使用准入控制器 此页面概述了准入控制器。
什么是准入控制插件? 准入控制器是一段代码,它会在请求通过认证和授权之后、对象被持久化之前拦截到达 API
服务器的请求。控制器由下面的列表 组成,
并编译进 kube-apiserver 二进制文件,并且只能由集群管理员配置。
在该列表中,有两个特殊的控制器:MutatingAdmissionWebhook 和 ValidatingAdmissionWebhook。
它们根据 API 中的配置,分别执行变更和验证
准入控制 webhook 。
准入控制器可以执行 “验证(Validating)” 和/或 “变更(Mutating)” 操作。
变更(mutating)控制器可以修改被其接受的对象;验证(validating)控制器则不行。
准入控制过程分为两个阶段。第一阶段,运行变更准入控制器。第二阶段,运行验证准入控制器。
再次提醒,某些控制器既是变更准入控制器又是验证准入控制器。
如果任何一个阶段的任何控制器拒绝了该请求,则整个请求将立即被拒绝,并向终端用户返回一个错误。
最后,除了对对象进行变更外,准入控制器还可以有其它作用:将相关资源作为请求处理的一部分进行变更。
增加使用配额就是一个典型的示例,说明了这样做的必要性。
此类用法都需要相应的回收或回调过程,因为任一准入控制器都无法确定某个请求能否通过所有其它准入控制器。
为什么需要准入控制器? Kubernetes 的许多高级功能都要求启用一个准入控制器,以便正确地支持该特性。
因此,没有正确配置准入控制器的 Kubernetes API 服务器是不完整的,它无法支持你期望的所有特性。
如何启用一个准入控制器? Kubernetes API 服务器的 enable-admission-plugins 标志接受一个用于在集群修改对象之前
调用的(以逗号分隔的)准入控制插件顺序列表。
例如,下面的命令就启用了 NamespaceLifecycle 和 LimitRanger 准入控制插件:
kube-apiserver --enable-admission-plugins= NamespaceLifecycle,LimitRanger ...
说明: 根据你 Kubernetes 集群的部署方式以及 API 服务器的启动方式的不同,你可能需要以不同的方式应用设置。
例如,如果将 API 服务器部署为 systemd 服务,你可能需要修改 systemd 单元文件;
如果以自托管方式部署 Kubernetes,你可能需要修改 API 服务器的清单文件。
怎么关闭准入控制器? Kubernetes API 服务器的 disable-admission-plugins 标志,会将传入的(以逗号分隔的)
准入控制插件列表禁用,即使是默认启用的插件也会被禁用。
kube-apiserver --disable-admission-plugins= PodNodeSelector,AlwaysDeny ...
哪些插件是默认启用的? 下面的命令可以查看哪些插件是默认启用的:
kube-apiserver -h | grep enable-admission-plugins
在目前版本中,它们是:
NamespaceLifecycle, LimitRanger, ServiceAccount, TaintNodesByCondition, Priority, DefaultTolerationSeconds, DefaultStorageClass, StorageObjectInUseProtection, PersistentVolumeClaimResize, RuntimeClass, CertificateApproval, CertificateSigning, CertificateSubjectRestriction, DefaultIngressClass, MutatingAdmissionWebhook, ValidatingAdmissionWebhook, ResourceQuota
每个准入控制器的作用是什么? AlwaysAdmit FEATURE STATE: Kubernetes v1.13 [deprecated]
该准入控制器会允许所有的 pod 接入集群。已废弃,因为它的行为根本就和没有准入控制器一样。
AlwaysPullImages 该准入控制器会修改每一个新创建的 Pod 的镜像拉取策略为 Always 。
这在多租户集群中是有用的,这样用户就可以放心,他们的私有镜像只能被那些有凭证的人使用。
如果没有这个准入控制器,一旦镜像被拉取到节点上,任何用户的 Pod 都可以通过已了解到的镜像
的名称(假设 Pod 被调度到正确的节点上)来使用它,而不需要对镜像进行任何授权检查。
当启用这个准入控制器时,总是在启动容器之前拉取镜像,这意味着需要有效的凭证。
AlwaysDeny FEATURE STATE: Kubernetes v1.13 [deprecated]
拒绝所有的请求。由于没有实际意义,已废弃。
CertificateApproval 此准入控制器获取“审批” CertificateSigningRequest 资源的请求并执行额外的授权检查,
以确保审批请求的用户有权限审批 spec.signerName 请求 CertificateSigningRequest 资源的证书请求。
有关对证书签名请求资源执行不同操作所需权限的详细信息,
请参阅证书签名请求
CertificateSigning 此准入控制器获取 CertificateSigningRequest 资源的 status.certificate 字段更新请求并执行额外的授权检查,
以确保签发证书的用户有权限为 spec.signerName 请求 CertificateSigningRequest 资源的证书请求签发证书。
有关对证书签名请求资源执行不同操作所需权限的详细信息,
请参阅证书签名请求
CertificateSubjectRestrictions 此准入控制器获取具有 kubernetes.io/kube-apiserver-client 的 spec.signerName 的
CertificateSigningRequest 资源创建请求,
它拒绝任何包含了 system:masters 一个“组”(或者“组织”)的请求。
DefaultStorageClass 该准入控制器监测没有请求任何特定存储类的 PersistentVolumeClaim 对象的创建,
并自动向其添加默认存储类。
这样,没有任何特殊存储类需求的用户根本不需要关心它们,它们将获得默认存储类。
当未配置默认存储类时,此准入控制器不执行任何操作。如果将多个存储类标记为默认存储类,
它将拒绝任何创建 PersistentVolumeClaim 的操作,并显示错误。
要修复此错误,管理员必须重新访问其 StorageClass 对象,并仅将其中一个标记为默认。
此准入控制器会忽略所有 PersistentVolumeClaim 更新操作,仅响应创建操作。
关于持久化卷和存储类,以及如何将存储类标记为默认,请参见
持久化卷 。
DefaultTolerationSeconds 该准入控制器为 Pod 设置默认的容忍度,在 5 分钟内容忍 notready:NoExecute 和
unreachable:NoExecute 污点。
(如果 Pod 尚未容忍 node.kubernetes.io/not-ready:NoExecute 和
node.kubernetes.io/unreachable:NoExecute 污点的话)
DenyExecOnPrivileged FEATURE STATE: Kubernetes v1.13 [deprecated]
如果一个 pod 拥有一个特权容器,该准入控制器将拦截所有在该 pod 中执行 exec 命令的请求。
此功能已合并至 DenyEscalatingExec 。
而 DenyExecOnPrivileged 准入插件已被废弃,并将在 v1.18 被移除。
建议使用基于策略的准入插件(例如 PodSecurityPolicy 和自定义准入插件),
该插件可以针对特定用户或名字空间,还可以防止创建权限过高的 Pod。
DenyEscalatingExec FEATURE STATE: Kubernetes v1.13 [deprecated]
该准入控制器将拒绝在由于拥有升级特权,而具备访问宿主机能力的 Pod 中执行 exec 和
attach 命令。这包括在特权模式运行的 Pod,可以访问主机 IPC 名字空间的 Pod,
和访问主机 PID 名字空间的 Pod 。
DenyExecOnPrivileged 准入插件已被废弃,并将在 v1.18 被移除。
建议使用基于策略的准入插件(例如 PodSecurityPolicy 和自定义准入插件),
该插件可以针对特定用户或名字空间,还可以防止创建权限过高的 Pod。
EventRateLimit FEATURE STATE: Kubernetes v1.13 [alpha]
该准入控制器缓解了事件请求淹没 API 服务器的问题。集群管理员可以通过以下方式指定事件速率限制:
启用 EventRateLimit 准入控制器; 从文件中引用 EventRateLimit 配置文件,并提供给 API 服务器命令的
--admission-control-config-file 标志:
apiVersion : apiserver.config.k8s.io/v1
kind : AdmissionConfiguration
plugins :
- name : EventRateLimit
path : eventconfig.yaml
...
# Deprecated in v1.17 in favor of apiserver.config.k8s.io/v1
apiVersion : apiserver.k8s.io/v1alpha1
kind : AdmissionConfiguration
plugins :
- name : EventRateLimit
path : eventconfig.yaml
...
可以在配置中指定四种类型的限制:
Server: API 服务器收到的所有事件请求共享一个桶。Namespace: 每个名字空间都有一个专用的桶。User: 给每个用户都分配一个桶。SourceAndObject: 根据事件的源和涉及对象的每种组合分配桶。下面是一个配置示例 eventconfig.yaml:
apiVersion : eventratelimit.admission.k8s.io/v1alpha1
kind : Configuration
limits :
- type : Namespace
qps : 50
burst : 100
cacheSize : 2000
- type : User
qps : 10
burst : 50
详情请参见
事件速率限制提案 。
ExtendedResourceToleration 该插件有助于创建可扩展资源的专用节点。
如果运营商想创建可扩展资源的专用节点(如 GPU、FPGA 等),
那他们应该以扩展资源名称作为键名,
为节点设置污点 。
如果启用了该准入控制器,会将此类污点的容忍自动添加到请求扩展资源的 Pod 中,
用户不必再手动添加这些容忍。
ImagePolicyWebhook ImagePolicyWebhook 准入控制器允许使用一个后端的 webhook 做出准入决策。
配置文件格式 ImagePolicyWebhook 使用配置文件来为后端行为设置配置选项。该文件可以是 JSON 或 YAML,
并具有以下格式:
imagePolicy :
kubeConfigFile : /path/to/kubeconfig/for/backend
# 以秒计的时长,控制批准请求的缓存时间
allowTTL : 50
# 以秒计的时长,控制批准请求的缓存时间
denyTTL : 50
# 以毫秒计的时长,控制重试间隔
retryBackoff : 500
# 确定 Webhook 后端失效时的行为
defaultAllow : true
从文件中引用 ImagePolicyWebhook 的配置文件,并将其提供给 API 服务器命令标志
--admission-control-config-file:
apiVersion : apiserver.config.k8s.io/v1
kind : AdmissionConfiguration
plugins :
- name : ImagePolicyWebhook
path : imagepolicyconfig.yaml
...
# v1.17 中已废弃以鼓励使用 apiserver.config.k8s.io/v1
apiVersion : apiserver.k8s.io/v1alpha1
kind : AdmissionConfiguration
plugins :
- name : ImagePolicyWebhook
path : imagepolicyconfig.yaml
...
或者,你也可以直接将配置嵌入到文件中:
apiVersion : apiserver.config.k8s.io/v1
kind : AdmissionConfiguration
plugins :
- name : ImagePolicyWebhook
configuration :
imagePolicy :
kubeConfigFile : <kubeconfig 文件路径>
allowTTL : 50
denyTTL : 50
retryBackoff : 500
defaultAllow : true
# v1.17 中已废弃以鼓励使用 apiserver.config.k8s.io/v1
apiVersion : apiserver.k8s.io/v1alpha1
kind : AdmissionConfiguration
plugins :
- name : ImagePolicyWebhook
configuration :
imagePolicy :
kubeConfigFile : <kubeconfig 文件路径>
allowTTL : 50
denyTTL : 50
retryBackoff : 500
defaultAllow : true
ImagePolicyWebhook 的配置文件必须引用
kubeconfig
格式的文件;该文件设置了到后端的连接参数。
要求后端使用 TLS 进行通信。
kubeconfig 文件的 cluster 字段需要指向远端服务,user 字段需要包含已返回的授权者。
# clusters 指的是远程服务。
clusters :
- name : name-of-remote-imagepolicy-service
cluster :
certificate-authority : /path/to/ca.pem # CA 用于验证远程服务
server : https://images.example.com/policy # 要查询的远程服务的 URL。必须是 'https' 。
# users 指的是 API 服务器的 Webhook 配置。
users :
- name : name-of-api-server
user :
client-certificate : /path/to/cert.pem # webhook 准入控制器使用的证书
client-key : /path/to/key.pem # 证书匹配的密钥
关于 HTTP 配置的更多信息,请参阅
kubeconfig
文档。
请求载荷 当面对一个准入决策时,API 服务器发送一个描述操作的 JSON 序列化的
imagepolicy.k8s.io/v1alpha1 ImageReview 对象。
该对象包含描述被审核容器的字段,以及所有匹配 *.image-policy.k8s.io/* 的
Pod 注解。
注意,Webhook API 对象与其他 Kubernetes API 对象一样受制于相同的版本控制兼容性规则。
实现者应该知道对 alpha 对象的更宽松的兼容性,并检查请求的 "apiVersion" 字段,
以确保正确的反序列化。
此外,API 服务器必须启用 imagepolicy.k8s.io/v1alpha1 API 扩展组
(--runtime-config=imagepolicy.k8s.io/v1alpha1=true)。
请求载荷示例:
{
"apiVersion" :"imagepolicy.k8s.io/v1alpha1" ,
"kind" :"ImageReview" ,
"spec" :{
"containers" :[
{
"image" :"myrepo/myimage:v1"
},
{
"image" :"myrepo/myimage@sha256:beb6bd6a68f114c1dc2ea4b28db81bdf91de202a9014972bec5e4d9171d90ed"
}
],
"annotations" :{
"mycluster.image-policy.k8s.io/ticket-1234" : "break-glass"
},
"namespace" :"mynamespace"
}
}
远程服务将填充请求的 ImageReviewStatus 字段,并返回允许或不允许访问的响应。
响应体的 "spec" 字段会被忽略,并且可以省略。一个允许访问应答会返回:
{
"apiVersion" : "imagepolicy.k8s.io/v1alpha1" ,
"kind" : "ImageReview" ,
"status" : {
"allowed" : true
}
}
若不允许访问,服务将返回:
{
"apiVersion" : "imagepolicy.k8s.io/v1alpha1" ,
"kind" : "ImageReview" ,
"status" : {
"allowed" : false ,
"reason" : "image currently blacklisted"
}
}
更多的文档,请参阅 imagepolicy.v1alpha1 API 对象和
plugin/pkg/admission/imagepolicy/admission.go。
使用注解进行扩展 一个 Pod 中匹配 *.image-policy.k8s.io/* 的注解都会被发送给 Webhook。
这样做使得了解后端镜像策略的用户可以向它发送额外的信息,并为不同的后端实现
接收不同的信息。
你可以在这里输入的信息有:
在紧急情况下,请求 "break glass" 覆盖一个策略。 从一个记录了 break-glass 的请求的 ticket 系统得到的一个 ticket 号码。 向策略服务器提供一个提示,用于提供镜像的 imageID,以方便它进行查找。 在任何情况下,注解都是由用户提供的,并不会被 Kubernetes 以任何方式进行验证。
在将来,如果一个注解确定将被广泛使用,它可能会被提升为 ImageReviewSpec 的一个命名字段。
LimitPodHardAntiAffinityTopology 该准入控制器拒绝(定义了 AntiAffinity 拓扑键的)任何 Pod
(requiredDuringSchedulingRequiredDuringExecution 中的
kubernetes.io/hostname 除外)。
LimitRanger 该准入控制器会观察传入的请求,并确保它不会违反 Namespace 中 LimitRange
对象枚举的任何约束。
如果你在 Kubernetes 部署中使用了 LimitRange 对象,则必须使用此准入控制器来
执行这些约束。
LimitRanger 还可以用于将默认资源请求应用到没有指定任何内容的 Pod;
当前,默认的 LimitRanger 对 default 名字空间中的所有 Pod 都应用了
0.1 CPU 的需求。
请查看
limitRange 设计文档
和 LimitRange 例子
以了解更多细节。
MutatingAdmissionWebhook FEATURE STATE: Kubernetes v1.13 [beta]
该准入控制器调用任何与请求匹配的变更 Webhook。匹配的 Webhook 将被串行调用。
每一个 Webhook 都可以根据需要修改对象。
MutatingAdmissionWebhook,顾名思义,仅在变更阶段运行。
如果由此准入控制器调用的 Webhook 有副作用(如降低配额),
则它 必须 具有协调系统,因为不能保证后续的 Webhook 和验证准入控制器都会允许完成请求。
如果你禁用了 MutatingAdmissionWebhook,那么还必须使用 --runtime-config 标志禁止
admissionregistration.k8s.io/v1beta1 组/版本中的 MutatingWebhookConfiguration
对象(版本 >=1.9 时,这两个对象都是默认启用的)。
谨慎编写和安装变更 webhook 当用户尝试创建的对象与返回的对象不同时,用户可能会感到困惑。 当它们回读的对象与尝试创建的对象不同,内建的控制环可能会出问题。与覆盖原始请求中设置的字段相比,使用原始请求未设置的字段会引起问题的可能性较小。
应尽量避免前面那种方式。 这是一个 beta 特性。Kubernetes 未来的版本可能会限制这些 Webhook 可以进行的变更类型。 内建资源和第三方资源的控制回路未来可能会受到破坏性的更改,使现在运行良好的 Webhook
无法再正常运行。即使完成了 Webhook API 安装,也不代表会为该 webhook 提供无限期的支持。 NamespaceAutoProvision 该准入控制器会检查名字空间资源上的所有传入请求,并检查所引用的名字空间是否确实存在。
如果找不到,它将创建一个名字空间。
此准入控制器对于不想要求名字空间必须先创建后使用的集群部署中很有用。
NamespaceExists 该准入控制器检查除 Namespace 以外的名字空间作用域资源上的所有请求。
如果请求引用的名字空间不存在,则拒绝该请求。
NamespaceLifecycle 该准入控制器禁止在一个正在被终止的 Namespace 中创建新对象,并确保
使用不存在的 Namespace 的请求被拒绝。
该准入控制器还会禁止删除三个系统保留的名字空间,即 default、
kube-system 和 kube-public。
删除 Namespace 会触发删除该名字空间中所有对象(Pod、Service 等)的一系列操作。
为了确保这个过程的完整性,我们强烈建议启用这个准入控制器。
NodeRestriction 该准入控制器限制了 kubelet 可以修改的 Node 和 Pod 对象。
为了受到这个准入控制器的限制,kubelet 必须使用在 system:nodes 组中的凭证,
并使用 system:node:<nodeName> 形式的用户名。
这样,kubelet 只可修改自己的 Node API 对象,只能修改绑定到节点本身的 Pod 对象。
在 Kubernetes 1.11+ 的版本中,不允许 kubelet 从 Node API 对象中更新或删除污点。
在 Kubernetes 1.13+ 的版本中,NodeRestriction 准入插件可防止 kubelet 删除
Node API 对象,并对 kubernetes.io/ 或 k8s.io/ 前缀标签的 kubelet
强制进行如下修改:
防止 kubelet 添加/删除/更新带有 node-restriction.kubernetes.io/ 前缀的标签。
保留此前缀的标签,供管理员用来标记 Node 对象以隔离工作负载,并且不允许 kubelet
修改带有该前缀的标签。允许 kubelet 添加/删除/更新这些和这些前缀的标签:kubernetes.io/hostnamekubernetes.io/archkubernetes.io/osbeta.kubernetes.io/instance-typenode.kubernetes.io/instance-typefailure-domain.beta.kubernetes.io/region (已弃用)failure-domain.beta.kubernetes.io/zone (已弃用)topology.kubernetes.io/regiontopology.kubernetes.io/zonekubelet.kubernetes.io/-prefixed labelsnode.kubernetes.io/-prefixed labelskubelet 保留 kubernetes.io 或 k8s.io 前缀的所有标签,并且将来可能会被
NodeRestriction 准入插件允许或禁止。
将来的版本可能会增加其他限制,以确保 kubelet 具有正常运行所需的最小权限集。
OwnerReferencesPermissionEnforcement 该准入控制器保护对 metadata.ownerReferences 对象的访问,以便只有对该对象具有
“删除” 权限的用户才能对其进行更改。
该准入控制器还保护对 metadata.ownerReferences[x].blockOwnerDeletion 对象的访问,
以便只有对所引用的 属主(owner) 的 finalizers 子资源具有 “更新”
权限的用户才能对其进行更改。
PersistentVolumeLabel FEATURE STATE: Kubernetes v1.13 [deprecated]
该准入控制器会自动将区(region)或区域(zone)标签附加到由云提供商(如 GCE、AWS)
定义的 PersistentVolume。这有助于确保 Pod 和 PersistentVolume 位于相同的区或区域。
如果准入控制器不支持为 PersistentVolumes 自动添加标签,那你可能需要手动添加标签,
以防止 Pod 挂载其他区域的卷。
PersistentVolumeLabel 已被废弃,标记持久卷已由
云管理控制器 接管。
从 1.11 开始,默认情况下禁用此准入控制器。
PodNodeSelector 该准入控制器通过读取名字空间注解和全局配置,来为名字空间中可以可以使用的节点选择器
设置默认值并实施限制。
配置文件格式 PodNodeSelector 使用配置文件来设置后端行为的选项。
请注意,配置文件格式将在将来某个版本中改为版本化文件。
该文件可以是 JSON 或 YAML,格式如下:
podNodeSelectorPluginConfig :
clusterDefaultNodeSelector : name-of-node-selector
namespace1 : name-of-node-selector
namespace2 : name-of-node-selector
基于提供给 API 服务器命令行标志 --admission-control-config-file 的文件名,
从文件中引用 PodNodeSelector 配置文件:
apiVersion : apiserver.config.k8s.io/v1
kind : AdmissionConfiguration
plugins :
- name : PodNodeSelector
path : podnodeselector.yaml
...
# 在 v1.17 中废弃,以鼓励使用 apiserver.config.k8s.io/v1
apiVersion : apiserver.k8s.io/v1alpha1
kind : AdmissionConfiguration
plugins :
- name : PodNodeSelector
path : podnodeselector.yaml
...
配置注解格式 PodNodeSelector 使用键为 scheduler.alpha.kubernetes.io/node-selector 的注解
为名字空间设置节点选择算符。
apiVersion : v1
kind : Namespace
metadata :
annotations :
scheduler.alpha.kubernetes.io/node-selector : name-of-node-selector
name : namespace3
内部行为 该准入控制器行为如下:
如果 Namespace 的注解带有键 scheduler.alpha.kubernetes.io/node-selector,
则将其值用作节点选择算符。 如果名字空间缺少此类注解,则使用 PodNodeSelector 插件配置文件中定义的
clusterDefaultNodeSelector 作为节点选择算符。 评估 Pod 节点选择算符和名字空间节点选择算符是否存在冲突。存在冲突将导致拒绝。 评估 pod 节点选择算符和名字空间的白名单定义的插件配置文件是否存在冲突。
存在冲突将导致拒绝。 说明: PodNodeSelector 允许 Pod 强制在特定标签的节点上运行。
另请参阅 PodTolerationRestriction 准入插件,该插件可防止 Pod 在特定污点的节点上运行。
PersistentVolumeClaimResize 该准入控制器检查传入的 PersistentVolumeClaim 调整大小请求,对其执行额外的验证操作。
说明: 对调整卷大小的支持是一种 Alpha 特性。管理员必须将特性门控 ExpandPersistentVolumes
设置为 true 才能启用调整大小。
启用 ExpandPersistentVolumes 特性门控之后,建议将 PersistentVolumeClaimResize
准入控制器也启用。除非 PVC 的 StorageClass 明确地将 allowVolumeExpansion 设置为
true 来显式启用调整大小。否则,默认情况下该准入控制器会阻止所有对 PVC 大小的调整。
例如:由以下 StorageClass 创建的所有 PersistentVolumeClaim 都支持卷容量扩充:
apiVersion : storage.k8s.io/v1
kind : StorageClass
metadata :
name : gluster-vol-default
provisioner : kubernetes.io/glusterfs
parameters :
resturl : "http://192.168.10.100:8080"
restuser : ""
secretNamespace : ""
secretName : ""
allowVolumeExpansion : true
关于持久化卷申领的更多信息,请参见
PersistentVolumeClaims 。
PodSecurityPolicy 此准入控制器负责在创建和修改 Pod 时根据请求的安全上下文和可用的 Pod
安全策略确定是否可以执行请求。
查看 Pod 安全策略文档
了解更多细节。
PodTolerationRestriction 准入控制器 PodTolerationRestriction 检查 Pod 的容忍度与其名字空间的容忍度之间
是否存在冲突。如果存在冲突,则拒绝 Pod 请求。
然后,它将名字空间的容忍度合并到 Pod 的容忍度中,之后根据名字空间的容忍度
白名单检查所得到的容忍度结果。如果检查成功,则将接受 Pod 请求,否则拒绝该请求。
如果 Pod 的名字空间没有任何关联的默认容忍度或容忍度白名单,则使用集群级别的
默认容忍度或容忍度白名单(如果有的话)。
名字空间的容忍度通过注解健 scheduler.alpha.kubernetes.io/defaultTolerations
来设置。可接受的容忍度可以通过 scheduler.alpha.kubernetes.io/tolerationsWhitelist
注解键来添加。
名字空间注解的示例:
apiVersion : v1
kind : Namespace
metadata :
name : apps-that-need-nodes-exclusively
annotations :
scheduler.alpha.kubernetes.io/defaultTolerations : '[{"operator": "Exists", "effect": "NoSchedule", "key": "dedicated-node"}]'
scheduler.alpha.kubernetes.io/tolerationsWhitelist : '[{"operator": "Exists", "effect": "NoSchedule", "key": "dedicated-node"}]'
优先级 优先级准入控制器使用 priorityClassName 字段并用整型值填充优先级。
如果找不到优先级,则拒绝 Pod。
ResourceQuota 该准入控制器会监测传入的请求,并确保它不违反任何一个 Namespace 中的 ResourceQuota
对象中枚举出来的约束。
如果你在 Kubernetes 部署中使用了 ResourceQuota,你必须使用这个准入控制器来强制
执行配额限制。
请查看
resourceQuota 设计文档 和 Resource Quota 例子
了解更多细节。
RuntimeClass +
FEATURE STATE: Kubernetes v1.20 [stable]
如果你开启 PodOverhead
特性门控 ,
并且通过 Pod 开销
配置来定义一个 RuntimeClass,这个准入控制器会检查新的 Pod。
当启用的时候,这个准入控制器会拒绝任何 overhead 字段已经设置的 Pod。
对于配置了 RuntimeClass 并在其 .spec 中选定 RuntimeClass 的 Pod,
此准入控制器会根据相应 RuntimeClass 中定义的值为 Pod 设置 .spec.overhead。
说明: Pod 的 .spec.overhead 字段和 RuntimeClass 的 .overhead 字段均为处于 beta 版本。
如果你未启用 PodOverhead 特性门控,则所有 Pod 均被视为未设置 .spec.overhead。
详情请参见 Pod 开销 。
SecurityContextDeny 该准入控制器将拒绝任何试图设置特定提升
SecurityContext
字段的 Pod,正如任务
为 Pod 或 Container 配置安全上下文
中所展示的那样。
如果集群没有使用 Pod 安全策略
来限制安全上下文所能获取的值集,那么应该启用这个功能。
ServiceAccount 此准入控制器实现了
ServiceAccount
的自动化。
如果你打算使用 Kubernetes 的 ServiceAccount 对象,我们强烈建议你使用这个准入控制器。
StorageObjectInUseProtection StorageObjectInUseProtection 插件将 kubernetes.io/pvc-protection 或
kubernetes.io/pv-protection finalizers 添加到新创建的持久化卷声明(PVC)
或持久化卷(PV)中。
如果用户尝试删除 PVC/PV,除非 PVC/PV 的保护控制器移除 finalizers,否则
PVC/PV 不会被删除。
有关更多详细信息,请参考
保护使用中的存储对象 。
TaintNodesByCondition FEATURE STATE: Kubernetes v1.12 [beta]
该准入控制器为新创建的节点添加 NotReady 和 NoSchedule
污点 。
这些污点能够避免一些竞态条件的发生,这类静态条件可能导致 Pod 在更新节点污点以准确
反映其所报告状况之前,就被调度到新节点上。
ValidatingAdmissionWebhook FEATURE STATE: Kubernetes v1.13 [beta]
该准入控制器调用与请求匹配的所有验证 Webhook。
匹配的 Webhook 将被并行调用。如果其中任何一个拒绝请求,则整个请求将失败。
该准入控制器仅在验证(Validating)阶段运行;与 MutatingAdmissionWebhook 准入控制器
所调用的 Webhook 相反,它调用的 Webhook 应该不会使对象出现变更。
如果以此方式调用的 Webhook 有其它作用(如,降低配额),则它必须具有协调机制。
这是因为无法保证后续的 Webhook 或其他有效的准入控制器都允许请求完成。
如果你禁用了 ValidatingAdmissionWebhook,还必须通过 --runtime-config 标志来禁用
admissionregistration.k8s.io/v1beta1 组/版本中的 ValidatingWebhookConfiguration
对象(默认情况下在 1.9 版和更高版本中均处于启用状态)。
有推荐的准入控制器吗? 有。推荐使用的准入控制器默认情况下都处于启用状态
(请查看这里 )。
因此,你无需显式指定它们。
你可以使用 --enable-admission-plugins 标志( 顺序不重要 )来启用默认设置以外的其他准入控制器。
说明: --admission-control 在 1.10 中已废弃,由 --enable-admission-plugins 取代。
6.5.5 - 动态准入控制 除了内置的 admission 插件 ,
准入插件可以作为扩展独立开发,并以运行时所配置的 Webhook 的形式运行。
此页面描述了如何构建、配置、使用和监视准入 Webhook。
什么是准入 Webhook? 准入 Webhook 是一种用于接收准入请求并对其进行处理的 HTTP 回调机制。
可以定义两种类型的准入 webhook,即
验证性质的准入 Webhook 和
修改性质的准入 Webhook 。
修改性质的准入 Webhook 会先被调用。它们可以更改发送到 API
服务器的对象以执行自定义的设置默认值操作。
在完成了所有对象修改并且 API 服务器也验证了所传入的对象之后,
验证性质的 Webhook 会被调用,并通过拒绝请求的方式来强制实施自定义的策略。
说明: 如果准入 Webhook 需要保证它们所看到的是对象的最终状态以实施某种策略。
则应使用验证性质的准入 Webhook,因为对象被修改性质 Webhook 看到之后仍然可能被修改。
尝试准入 Webhook 准入 Webhook 本质上是集群控制平面的一部分。你应该非常谨慎地编写和部署它们。
如果你打算编写或者部署生产级准入 webhook,请阅读用户指南 以获取相关说明。
在下文中,我们将介绍如何快速试验准入 Webhook。
先决条件 确保 Kubernetes 集群版本至少为 v1.16(以便使用 admissionregistration.k8s.io/v1 API) 或者 v1.9 (以便使用 admissionregistration.k8s.io/v1beta1 API)。
确保启用 MutatingAdmissionWebhook 和 ValidatingAdmissionWebhook 控制器。
这里
是一组推荐的 admission 控制器,通常可以启用。
确保启用了 admissionregistration.k8s.io/v1beta1 API。
编写一个准入 Webhook 服务器 请参阅 Kubernetes e2e 测试中的 admission webhook 服务器 的实现。webhook 处理由 apiserver 发送的 AdmissionReview 请求,并且将其决定作为 AdmissionReview 对象以相同版本发送回去。
有关发送到 webhook 的数据的详细信息,请参阅 webhook 请求 。
要获取来自 webhook 的预期数据,请参阅 webhook 响应 。
示例准入 Webhook 服务器置 ClientAuth 字段为空 ,默认为 NoClientCert 。这意味着 webhook 服务器不会验证客户端的身份,认为其是 apiservers。
如果你需要双向 TLS 或其他方式来验证客户端,请参阅如何对 apiservers 进行身份认证 。
部署准入 Webhook 服务 e2e 测试中的 webhook 服务器通过 deployment API 部署在 Kubernetes 集群中。该测试还将创建一个 service 作为 webhook 服务器的前端。参见相关代码 。
你也可以在集群外部署 webhook。这样做需要相应地更新你的 webhook 配置。
即时配置准入 Webhook 你可以通过 ValidatingWebhookConfiguration 或者 MutatingWebhookConfiguration 动态配置哪些资源要被哪些准入 Webhook 处理。
以下是一个 ValidatingWebhookConfiguration 示例,mutating webhook 配置与此类似。有关每个配置字段的详细信息,请参阅 webhook 配置 部分。
apiVersion : admissionregistration.k8s.io/v1
kind : ValidatingWebhookConfiguration
metadata :
name : "pod-policy.example.com"
webhooks :
- name : "pod-policy.example.com"
rules :
- apiGroups : ["" ]
apiVersions : ["v1" ]
operations : ["CREATE" ]
resources : ["pods" ]
scope : "Namespaced"
clientConfig :
service :
namespace : "example-namespace"
name : "example-service"
caBundle : "Ci0tLS0tQk...<base64-encoded PEM bundle containing the CA that signed the webhook's serving certificate>...tLS0K"
admissionReviewVersions : ["v1" , "v1beta1" ]
sideEffects : None
timeoutSeconds : 5
# 1.16 中被淘汰,推荐使用 admissionregistration.k8s.io/v1
apiVersion : admissionregistration.k8s.io/v1beta1
kind : ValidatingWebhookConfiguration
metadata :
name : "pod-policy.example.com"
webhooks :
- name : "pod-policy.example.com"
rules :
- apiGroups : ["" ]
apiVersions : ["v1" ]
operations : ["CREATE" ]
resources : ["pods" ]
scope : "Namespaced"
clientConfig :
service :
namespace : "example-namespace"
name : "example-service"
caBundle : "Ci0tLS0tQk...<base64-encoded PEM bundle containing the CA that signed the webhook's serving certificate>...tLS0K"
admissionReviewVersions : ["v1beta1" ]
timeoutSeconds : 5
scope 字段指定是仅集群范围的资源(Cluster)还是名字空间范围的资源资源(Namespaced)将与此规则匹配。* 表示没有范围限制。
说明: 当使用 clientConfig.service 时,服务器证书必须对 <svc_name>.<svc_namespace>.svc 有效。
说明: 对于使用 admissionregistration.k8s.io/v1 创建的 webhook 而言,其 webhook 调用的默认超时是 10 秒;
对于使用 admissionregistration.k8s.io/v1beta1 创建的 webhook 而言,其默认超时是 30 秒。
从 kubernetes 1.14 开始,可以设置超时。建议对 webhooks 设置较短的超时时间。
如果 webhook 调用超时,则根据 webhook 的失败策略处理请求。
当 apiserver 收到与 rules 相匹配的请求时,apiserver 按照 clientConfig 中指定的方式向 webhook 发送一个 admissionReview 请求。
创建 webhook 配置后,系统将花费几秒钟使新配置生效。
对 apiservers 进行身份认证 如果你的 webhook 需要身份验证,则可以将 apiserver 配置为使用基本身份验证、持有者令牌或证书来向 webhook 提供身份证明。完成此配置需要三个步骤。
启动 apiserver 时,通过 --admission-control-config-file 参数指定准入控制配置文件的位置。
在准入控制配置文件中,指定 MutatingAdmissionWebhook 控制器和 ValidatingAdmissionWebhook 控制器应该读取凭据的位置。
凭证存储在 kubeConfig 文件中(是的,与 kubectl 使用的模式相同),因此字段名称为 kubeConfigFile。
以下是一个准入控制配置文件示例:
apiVersion : apiserver.config.k8s.io/v1
kind : AdmissionConfiguration
plugins :
- name : ValidatingAdmissionWebhook
configuration :
apiVersion : apiserver.config.k8s.io/v1
kind : WebhookAdmissionConfiguration
kubeConfigFile : "<path-to-kubeconfig-file>"
- name : MutatingAdmissionWebhook
configuration :
apiVersion : apiserver.config.k8s.io/v1
kind : WebhookAdmissionConfiguration
kubeConfigFile : "<path-to-kubeconfig-file>"
# 1.17 中被淘汰,推荐使用 apiserver.config.k8s.io/v1
apiVersion : apiserver.k8s.io/v1alpha1
kind : AdmissionConfiguration
plugins :
- name : ValidatingAdmissionWebhook
configuration :
# 1.17 中被淘汰,推荐使用 apiserver.config.k8s.io/v1,kind = WebhookAdmissionConfiguration
apiVersion : apiserver.config.k8s.io/v1alpha1
kind : WebhookAdmission
kubeConfigFile : "<path-to-kubeconfig-file>"
- name : MutatingAdmissionWebhook
configuration :
# 1.17 中被淘汰,推荐使用 apiserver.config.k8s.io/v1,kind = WebhookAdmissionConfiguration
apiVersion : apiserver.config.k8s.io/v1alpha1
kind : WebhookAdmission
kubeConfigFile : "<path-to-kubeconfig-file>"
有关 AdmissionConfiguration 的更多信息,请参见 AdmissionConfiguration schema 。
有关每个配置字段的详细信息,请参见 webhook 配置 部分。
在 kubeConfig 文件中,提供证书凭据:
apiVersion : v1
kind : Config
users :
# 名称应设置为服务的 DNS 名称或配置了 Webhook 的 URL 的主机名(包括端口)。
# 如果将非 443 端口用于服务,则在配置 1.16+ API 服务器时,该端口必须包含在名称中。
#
# 对于配置在默认端口(443)上与服务对话的 Webhook,请指定服务的 DNS 名称:
# - name: webhook1.ns1.svc
# user: ...
#
# 对于配置在非默认端口(例如 8443)上与服务对话的 Webhook,请在 1.16+ 中指定服务的 DNS 名称和端口:
# - name: webhook1.ns1.svc:8443
# user: ...
# 并可以选择仅使用服务的 DNS 名称来创建第二节,以与 1.15 API 服务器版本兼容:
# - name: webhook1.ns1.svc
# user: ...
#
# 对于配置为使用 URL 的 webhook,请匹配在 webhook 的 URL 中指定的主机(和端口)。
# 带有 `url: https://www.example.com` 的 webhook:
# - name: www.example.com
# user: ...
#
# 带有 `url: https://www.example.com:443` 的 webhook:
# - name: www.example.com:443
# user: ...
#
# 带有 `url: https://www.example.com:8443` 的 webhook:
# - name: www.example.com:8443
# user: ...
#
- name : 'webhook1.ns1.svc'
user :
client-certificate-data : "<pem encoded certificate>"
client-key-data : "<pem encoded key>"
# `name` 支持使用 * 通配符匹配前缀段。
- name : '*.webhook-company.org'
user :
password : "<password>"
username : "<name>"
# '*' 是默认匹配项。
- name : '*'
user :
token : "<token>"
当然,你需要设置 webhook 服务器来处理这些身份验证。
请求 向 Webhook 发送 POST 请求时,请设置 Content-Type: application/json 并对 admission.k8s.io API 组中的 AdmissionReview 对象进行序列化,将所得到的 JSON 作为请求的主体。
Webhook 可以在配置中的 admissionReviewVersions 字段指定可接受的 AdmissionReview 对象版本:
apiVersion : admissionregistration.k8s.io/v1
kind : ValidatingWebhookConfiguration
...
webhooks :
- name : my-webhook.example.com
admissionReviewVersions : ["v1" , "v1beta1" ]
...
创建 admissionregistration.k8s.io/v1 webhook 配置时,admissionReviewVersions 是必填字段。
Webhook 必须支持至少一个当前和以前的 apiserver 都可以解析的 AdmissionReview 版本。
# v1.16 中被淘汰,推荐使用 admissionregistration.k8s.io/v1
apiVersion : admissionregistration.k8s.io/v1beta1
kind : ValidatingWebhookConfiguration
...
webhooks :
- name : my-webhook.example.com
admissionReviewVersions : ["v1beta1" ]
...
如果未指定 admissionReviewVersions,则创建 admissionregistration.k8s.io/v1beta1 Webhook 配置时的默认值为 v1beta1。
API 服务器将发送的是 admissionReviewVersions 列表中所支持的第一个 AdmissionReview 版本。如果 API 服务器不支持列表中的任何版本,则不允许创建配置。
如果 API 服务器遇到以前创建的 Webhook 配置,并且不支持该 API 服务器知道如何发送的任何 AdmissionReview 版本,则调用 Webhook 的尝试将失败,并依据失败策略 进行处理。
此示例显示了 AdmissionReview 对象中包含的数据,该数据用于请求更新 apps/v1 Deployment 的 scale 子资源:
{
"apiVersion": "admission.k8s.io/v1" ,
"kind": "AdmissionReview" ,
"request": {
# 唯一标识此准入回调的随机 uid
"uid": "705ab4f5-6393-11e8-b7cc-42010a800002" ,
# 传入完全正确的 group/version/kind 对象
"kind": {"group" :"autoscaling" ,"version" :"v1" ,"kind" :"Scale" },
# 修改 resource 的完全正确的的 group/version/kind
"resource": {"group" :"apps" ,"version" :"v1" ,"resource" :"deployments" },
# subResource(如果请求是针对 subResource 的)
"subResource": "scale" ,
# 在对 API 服务器的原始请求中,传入对象的标准 group/version/kind
# 仅当 webhook 指定 `matchPolicy: Equivalent` 且将对 API 服务器的原始请求转换为 webhook 注册的版本时,这才与 `kind` 不同。
"requestKind": {"group" :"autoscaling" ,"version" :"v1" ,"kind" :"Scale" },
# 在对 API 服务器的原始请求中正在修改的资源的标准 group/version/kind
# 仅当 webhook 指定了 `matchPolicy:Equivalent` 并且将对 API 服务器的原始请求转换为 webhook 注册的版本时,这才与 `resource` 不同。
"requestResource": {"group" :"apps" ,"version" :"v1" ,"resource" :"deployments" },
# subResource(如果请求是针对 subResource 的)
# 仅当 webhook 指定了 `matchPolicy:Equivalent` 并且将对 API 服务器的原始请求转换为该 webhook 注册的版本时,这才与 `subResource` 不同。
"requestSubResource": "scale" ,
# 被修改资源的名称
"name": "my-deployment" ,
# 如果资源是属于名字空间(或者是名字空间对象),则这是被修改的资源的名字空间
"namespace": "my-namespace" ,
# 操作可以是 CREATE、UPDATE、DELETE 或 CONNECT
"operation": "UPDATE" ,
"userInfo": {
# 向 API 服务器发出请求的经过身份验证的用户的用户名
"username": "admin" ,
# 向 API 服务器发出请求的经过身份验证的用户的 UID
"uid": "014fbff9a07c" ,
# 向 API 服务器发出请求的经过身份验证的用户的组成员身份
"groups": ["system:authenticated" ,"my-admin-group" ],
# 向 API 服务器发出请求的用户相关的任意附加信息
# 该字段由 API 服务器身份验证层填充,并且如果 webhook 执行了任何 SubjectAccessReview 检查,则应将其包括在内。
"extra": {
"some-key" :["some-value1" , "some-value2" ]
}
},
# object 是被接纳的新对象。
# 对于 DELETE 操作,它为 null。
"object": {"apiVersion" :"autoscaling/v1" ,"kind" :"Scale" ,...},
# oldObject 是现有对象。
# 对于 CREATE 和 CONNECT 操作,它为 null。
"oldObject": {"apiVersion" :"autoscaling/v1" ,"kind" :"Scale" ,...},
# options 包含要接受的操作的选项,例如 meta.k8s.io/v CreateOptions、UpdateOptions 或 DeleteOptions。
# 对于 CONNECT 操作,它为 null。
"options": {"apiVersion" :"meta.k8s.io/v1" ,"kind" :"UpdateOptions" ,...},
# dryRun 表示 API 请求正在以 `dryrun` 模式运行,并且将不会保留。
# 带有副作用的 Webhook 应该避免在 dryRun 为 true 时激活这些副作用。
# 有关更多详细信息,请参见 http://k8s.io/docs/reference/using-api/api-concepts/#make-a-dry-run-request
"dryRun": false
}
}
{
# v1.16 中被废弃,推荐使用 admission.k8s.io/v1
"apiVersion": "admission.k8s.io/v1beta1" ,
"kind": "AdmissionReview" ,
"request": {
# 唯一标识此准入回调的随机 uid
"uid": "705ab4f5-6393-11e8-b7cc-42010a800002" ,
# 传入完全正确的 group/version/kind 对象
"kind": {"group" :"autoscaling" ,"version" :"v1" ,"kind" :"Scale" },
# 修改 resource 的完全正确的的 group/version/kind
"resource": {"group" :"apps" ,"version" :"v1" ,"resource" :"deployments" },
# subResource(如果请求是针对 subResource 的)
"subResource": "scale" ,
# 在对 API 服务器的原始请求中,传入对象的标准 group/version/kind。
# 仅当 Webhook 指定了 `matchPolicy:Equivalent` 并且将对 API 服务器的原始请求转换为该 Webhook 注册的版本时,这与 `kind` 不同。
# 仅由 v1.15+ API 服务器发送。
"requestKind": {"group" :"autoscaling" ,"version" :"v1" ,"kind" :"Scale" },
# 在对 API 服务器的原始请求中正在修改的资源的标准 group/version/kind
# 仅当 webhook 指定了 `matchPolicy:Equivalent` 并且将对 API 服务器的原始请求转换为 webhook 注册的版本时,这才与 `resource` 不同。
# 仅由 v1.15+ API 服务器发送。
"requestResource": {"group" :"apps" ,"version" :"v1" ,"resource" :"deployments" },
# subResource(如果请求是针对 subResource 的)
# 仅当 webhook 指定了 `matchPolicy:Equivalent` 并且将对 API 服务器的原始请求转换为该 webhook 注册的版本时,这才与 `subResource` 不同。
# 仅由 v1.15+ API 服务器发送。
"requestSubResource": "scale" ,
# 被修改资源的名称
"name": "my-deployment" ,
# 如果资源是属于名字空间(或者是名字空间对象),则这是被修改的资源的名字空间
"namespace": "my-namespace" ,
# 操作可以是 CREATE、UPDATE、DELETE 或 CONNECT
"operation": "UPDATE" ,
"userInfo": {
# 向 API 服务器发出请求的经过身份验证的用户的用户名
"username": "admin" ,
# 向 API 服务器发出请求的经过身份验证的用户的 UID
"uid": "014fbff9a07c" ,
# 向 API 服务器发出请求的经过身份验证的用户的组成员身份
"groups": ["system:authenticated" ,"my-admin-group" ],
# 向 API 服务器发出请求的用户相关的任意附加信息
# 该字段由 API 服务器身份验证层填充,并且如果 webhook 执行了任何 SubjectAccessReview 检查,则应将其包括在内。
"extra": {
"some-key" :["some-value1" , "some-value2" ]
}
},
# object 是被接纳的新对象。
# 对于 DELETE 操作,它为 null。
"object": {"apiVersion" :"autoscaling/v1" ,"kind" :"Scale" ,...},
# oldObject 是现有对象。
# 对于 CREATE 和 CONNECT 操作(对于 v1.15.0 之前版本的 API 服务器中的 DELETE 操作),它为 null。
"oldObject": {"apiVersion" :"autoscaling/v1" ,"kind" :"Scale" ,...},
# options 包含要接受的操作的选项,例如 meta.k8s.io/v CreateOptions、UpdateOptions 或 DeleteOptions。
# 对于 CONNECT 操作,它为 null。
# 仅由 v1.15+ API 服务器发送。
"options": {"apiVersion" :"meta.k8s.io/v1" ,"kind" :"UpdateOptions" ,...},
# dryRun 表示 API 请求正在以 `dryrun` 模式运行,并且将不会保留。
# 带有副作用的 Webhook 应该避免在 dryRun 为 true 时激活这些副作用。
# 有关更多详细信息,请参见 http://k8s.io/docs/reference/using-api/api-concepts/#make-a-dry-run-request
"dryRun": false
}
}
响应 Webhook 使用 HTTP 200 状态码、Content-Type: application/json 和一个包含 AdmissionReview 对象的 JSON 序列化格式来发送响应。该 AdmissionReview 对象与发送的版本相同,且其中包含的 response 字段已被有效填充。
response 至少必须包含以下字段:
uid,从发送到 webhook 的 request.uid 中复制而来allowed,设置为 true 或 falseWebhook 允许请求的最简单响应示例:
{
"apiVersion" : "admission.k8s.io/v1" ,
"kind" : "AdmissionReview" ,
"response" : {
"uid" : "<value from request.uid>" ,
"allowed" : true
}
}
{
"apiVersion" : "admission.k8s.io/v1beta1" ,
"kind" : "AdmissionReview" ,
"response" : {
"uid" : "<value from request.uid>" ,
"allowed" : true
}
}
Webhook 禁止请求的最简单响应示例:
{
"apiVersion" : "admission.k8s.io/v1" ,
"kind" : "AdmissionReview" ,
"response" : {
"uid" : "<value from request.uid>" ,
"allowed" : false
}
}
{
"apiVersion" : "admission.k8s.io/v1beta1" ,
"kind" : "AdmissionReview" ,
"response" : {
"uid" : "<value from request.uid>" ,
"allowed" : false
}
}
当拒绝请求时,Webhook 可以使用 status 字段自定义 http 响应码和返回给用户的消息。
有关状态类型的详细信息,请参见
API 文档 。
禁止请求的响应示例,它定制了向用户显示的 HTTP 状态码和消息:
{
"apiVersion" : "admission.k8s.io/v1" ,
"kind" : "AdmissionReview" ,
"response" : {
"uid" : "<value from request.uid>" ,
"allowed" : false ,
"status" : {
"code" : 403 ,
"message" : "You cannot do this because it is Tuesday and your name starts with A"
}
}
}
{
"apiVersion" : "admission.k8s.io/v1beta1" ,
"kind" : "AdmissionReview" ,
"response" : {
"uid" : "<value from request.uid>" ,
"allowed" : false ,
"status" : {
"code" : 403 ,
"message" : "You cannot do this because it is Tuesday and your name starts with A"
}
}
}
当允许请求时,mutating准入 Webhook 也可以选择修改传入的对象。
这是通过在响应中使用 patch 和 patchType 字段来完成的。
当前唯一支持的 patchType 是 JSONPatch。
有关更多详细信息,请参见 JSON patch 。
对于 patchType: JSONPatch,patch 字段包含一个以 base64 编码的 JSON patch 操作数组。
例如,设置 spec.replicas 的单个补丁操作将是
[{"op": "add", "path": "/spec/replicas", "value": 3}]。
如果以 Base64 形式编码,结果将是
W3sib3AiOiAiYWRkIiwgInBhdGgiOiAiL3NwZWMvcmVwbGljYXMiLCAidmFsdWUiOiAzfV0=
因此,添加该标签的 webhook 响应为:
{
"apiVersion" : "admission.k8s.io/v1" ,
"kind" : "AdmissionReview" ,
"response" : {
"uid" : "<value from request.uid>" ,
"allowed" : true ,
"patchType" : "JSONPatch" ,
"patch" : "W3sib3AiOiAiYWRkIiwgInBhdGgiOiAiL3NwZWMvcmVwbGljYXMiLCAidmFsdWUiOiAzfV0="
}
}
{
"apiVersion" : "admission.k8s.io/v1beta1" ,
"kind" : "AdmissionReview" ,
"response" : {
"uid" : "<value from request.uid>" ,
"allowed" : true ,
"patchType" : "JSONPatch" ,
"patch" : "W3sib3AiOiAiYWRkIiwgInBhdGgiOiAiL3NwZWMvcmVwbGljYXMiLCAidmFsdWUiOiAzfV0="
}
}
Webhook 配置 要注册准入 Webhook,请创建 MutatingWebhookConfiguration 或
ValidatingWebhookConfiguration API 对象。
每种配置可以包含一个或多个 Webhook。如果在单个配置中指定了多个
Webhook,则应为每个 webhook 赋予一个唯一的名称。
这在 admissionregistration.k8s.io/v1 中是必需的,但是在使用
admissionregistration.k8s.io/v1beta1 时强烈建议使用,
以使生成的审核日志和指标更易于与活动配置相匹配。
每个 Webhook 定义以下内容。
匹配请求-规则 每个 webhook 必须指定用于确定是否应将对 apiserver 的请求发送到 webhook 的规则列表。
每个规则都指定一个或多个 operations、apiGroups、apiVersions 和 resources 以及资源的 scope:
operations 列出一个或多个要匹配的操作。
可以是 CREATE、UPDATE、DELETE、CONNECT 或 * 以匹配所有内容。apiGroups 列出了一个或多个要匹配的 API 组。"" 是核心 API 组。"*" 匹配所有 API 组。apiVersions 列出了一个或多个要匹配的 API 版本。"*" 匹配所有 API 版本。resources 列出了一个或多个要匹配的资源。"*" 匹配所有资源,但不包括子资源。"*/*" 匹配所有资源,包括子资源。"pods/*" 匹配 pod 的所有子资源。"*/status" 匹配所有 status 子资源。scope 指定要匹配的范围。有效值为 "Cluster"、"Namespaced" 和 "*"。
子资源匹配其父资源的范围。在 Kubernetes v1.14+ 版本中才被支持。
默认值为 "*",对应 1.14 版本之前的行为。"Cluster" 表示只有集群作用域的资源才能匹配此规则(API 对象 Namespace 是集群作用域的)。"Namespaced" 意味着仅具有名字空间的资源才符合此规则。"*" 表示没有范围限制。如果传入请求与任何 Webhook 规则的指定操作、组、版本、资源和范围匹配,则该请求将发送到 Webhook。
以下是可用于指定应拦截哪些资源的规则的其他示例。
匹配针对 apps/v1 和 apps/v1beta1 组中 deployments 和 replicasets
资源的 CREATE 或 UPDATE 请求:
apiVersion : admissionregistration.k8s.io/v1
kind : ValidatingWebhookConfiguration
...
webhooks :
- name : my-webhook.example.com
rules :
- operations : ["CREATE" , "UPDATE" ]
apiGroups : ["apps" ]
apiVersions : ["v1" , "v1beta1" ]
resources : ["deployments" , "replicasets" ]
scope : "Namespaced"
...
# v1.16 中被废弃,推荐使用 admissionregistration.k8s.io/v1
apiVersion : admissionregistration.k8s.io/v1beta1
kind : ValidatingWebhookConfiguration
...
webhooks :
- name : my-webhook.example.com
rules :
- operations : ["CREATE" , "UPDATE" ]
apiGroups : ["apps" ]
apiVersions : ["v1" , "v1beta1" ]
resources : ["deployments" , "replicasets" ]
scope : "Namespaced"
...
匹配所有 API 组和版本中的所有资源(但不包括子资源)的创建请求:
apiVersion : admissionregistration.k8s.io/v1
kind : ValidatingWebhookConfiguration
...
webhooks :
- name : my-webhook.example.com
rules :
- operations : ["CREATE" ]
apiGroups : ["*" ]
apiVersions : ["*" ]
resources : ["*" ]
scope : "*"
...
# v1.16 中被废弃,推荐使用 admissionregistration.k8s.io/v1
apiVersion : admissionregistration.k8s.io/v1beta1
kind : ValidatingWebhookConfiguration
...
webhooks :
- name : my-webhook.example.com
rules :
- operations : ["CREATE" ]
apiGroups : ["*" ]
apiVersions : ["*" ]
resources : ["*" ]
scope : "*"
...
匹配所有 API 组和版本中所有 status 子资源的更新请求:
apiVersion : admissionregistration.k8s.io/v1
kind : ValidatingWebhookConfiguration
...
webhooks :
- name : my-webhook.example.com
rules :
- operations : ["CREATE" ]
apiGroups : ["*" ]
apiVersions : ["*" ]
resources : ["*" ]
scope : "*"
...
# v1.16 中被废弃,推荐使用 admissionregistration.k8s.io/v1
apiVersion : admissionregistration.k8s.io/v1beta1
kind : ValidatingWebhookConfiguration
...
webhooks :
- name : my-webhook.example.com
rules :
- operations : ["CREATE" ]
apiGroups : ["*" ]
apiVersions : ["*" ]
resources : ["*" ]
scope : "*"
...
匹配请求:objectSelector 在版本 v1.15+ 中, 通过指定 objectSelector,Webhook 能够根据
可能发送的对象的标签来限制哪些请求被拦截。
如果指定,则将对 objectSelector 和可能发送到 Webhook 的 object 和 oldObject
进行评估。如果两个对象之一与选择器匹配,则认为该请求已匹配。
空对象(对于创建操作而言为 oldObject,对于删除操作而言为 newObject),
或不能带标签的对象(例如 DeploymentRollback 或 PodProxyOptions 对象)
被认为不匹配。
仅当选择使用 webhook 时才使用对象选择器,因为最终用户可以通过设置标签来
跳过准入 Webhook。
这个例子展示了一个 mutating webhook,它将匹配带有标签 foo:bar 的任何资源的
CREATE 的操作:
apiVersion : admissionregistration.k8s.io/v1
kind : MutatingWebhookConfiguration
...
webhooks :
- name : my-webhook.example.com
objectSelector :
matchLabels :
foo : bar
rules :
- operations : ["CREATE" ]
apiGroups : ["*" ]
apiVersions : ["*" ]
resources : ["*" ]
scope : "*"
...
# v1.16 中被废弃,推荐使用 admissionregistration.k8s.io/v1
apiVersion : admissionregistration.k8s.io/v1beta1
kind : MutatingWebhookConfiguration
...
webhooks :
- name : my-webhook.example.com
objectSelector :
matchLabels :
foo : bar
rules :
- operations : ["CREATE" ]
apiGroups : ["*" ]
apiVersions : ["*" ]
resources : ["*" ]
scope : "*"
...
有关标签选择器的更多示例,请参见标签 。
匹配请求:namespaceSelector 通过指定 namespaceSelector,Webhook 可以根据具有名字空间的资源所处的
名字空间的标签来选择拦截哪些资源的操作。
namespaceSelector 根据名字空间的标签是否匹配选择器,决定是否针对具名字空间的资源
(或 Namespace 对象)的请求运行 webhook。
如果对象是除 Namespace 以外的集群范围的资源,则 namespaceSelector 标签无效。
本例给出的修改性质的 Webhook 将匹配到对名字空间中具名字空间的资源的 CREATE 请求,
前提是这些资源不含值为 "0" 或 "1" 的 "runlevel" 标签:
apiVersion : admissionregistration.k8s.io/v1
kind : MutatingWebhookConfiguration
...
webhooks :
- name : my-webhook.example.com
namespaceSelector :
matchExpressions :
- key : runlevel
operator : NotIn
values : ["0" ,"1" ]
rules :
- operations : ["CREATE" ]
apiGroups : ["*" ]
apiVersions : ["*" ]
resources : ["*" ]
scope : "Namespaced"
...
# v1.16 中被废弃,推荐使用 admissionregistration.k8s.io/v1
apiVersion : admissionregistration.k8s.io/v1beta1
kind : MutatingWebhookConfiguration
...
webhooks :
- name : my-webhook.example.com
namespaceSelector :
matchExpressions :
- key : runlevel
operator : NotIn
values : ["0" ,"1" ]
rules :
- operations : ["CREATE" ]
apiGroups : ["*" ]
apiVersions : ["*" ]
resources : ["*" ]
scope : "Namespaced"
...
此示例显示了一个验证性质的 Webhook,它将匹配到对某名字空间中的任何具名字空间的资源的
CREATE 请求,前提是该名字空间具有值为 "prod" 或 "staging" 的 "environment" 标签:
apiVersion : admissionregistration.k8s.io/v1
kind : ValidatingWebhookConfiguration
...
webhooks :
- name : my-webhook.example.com
namespaceSelector :
matchExpressions :
- key : environment
operator : In
values : ["prod" ,"staging" ]
rules :
- operations : ["CREATE" ]
apiGroups : ["*" ]
apiVersions : ["*" ]
resources : ["*" ]
scope : "Namespaced"
...
# v1.16 中被废弃,推荐使用 admissionregistration.k8s.io/v1
apiVersion : admissionregistration.k8s.io/v1beta1
kind : ValidatingWebhookConfiguration
...
webhooks :
- name : my-webhook.example.com
namespaceSelector :
matchExpressions :
- key : environment
operator : In
values : ["prod" ,"staging" ]
rules :
- operations : ["CREATE" ]
apiGroups : ["*" ]
apiVersions : ["*" ]
resources : ["*" ]
scope : "Namespaced"
...
有关标签选择器的更多示例,请参见
标签 。
匹配请求:matchPolicy API 服务器可以通过多个 API 组或版本来提供对象。
例如,Kubernetes API 服务器允许通过 extensions/v1beta1、apps/v1beta1、
apps/v1beta2 和 apps/v1 API 创建和修改 Deployment 对象。
例如,如果一个 webhook 仅为某些 API 组/版本指定了规则(例如
apiGroups:["apps"], apiVersions:["v1","v1beta1"]),而修改资源的请求
是通过另一个 API 组/版本(例如 extensions/v1beta1)发出的,
该请求将不会被发送到 Webhook。
在 v1.15+ 中,matchPolicy 允许 webhook 定义如何使用其 rules 匹配传入的请求。
允许的值为 Exact 或 Equivalent。
Exact 表示仅当请求与指定规则完全匹配时才应拦截该请求。Equivalent 表示如果某个请求意在修改 rules 中列出的资源,
即使该请求是通过其他 API 组或版本发起,也应拦截该请求。在上面给出的示例中,仅为 apps/v1 注册的 webhook 可以使用 matchPolicy:
matchPolicy: Exact 表示不会将 extensions/v1beta1 请求发送到 WebhookmatchPolicy:Equivalent 表示将 extensions/v1beta1 请求发送到 webhook
(将对象转换为 webhook 指定的版本:apps/v1)建议指定 Equivalent,确保升级后启用 API 服务器中资源的新版本时,
Webhook 继续拦截他们期望的资源。
当 API 服务器停止提供某资源时,该资源不再被视为等同于该资源的其他仍在提供服务的版本。
例如,extensions/v1beta1 中的 Deployment 已被废弃,计划在 v1.16 中默认停止使用。
在这种情况下,带有 apiGroups:["extensions"], apiVersions:["v1beta1"], resources: ["deployments"]
规则的 Webhook 将不再拦截通过 apps/v1 API 来创建 Deployment 的请求。
["deployments"] 规则将不再拦截通过 apps/v1 API 创建的部署。
此示例显示了一个验证性质的 Webhook,该 Webhook 拦截对 Deployment 的修改(无论 API 组或版本是什么),
始终会发送一个 apps/v1 版本的 Deployment 对象:
apiVersion : admissionregistration.k8s.io/v1
kind : ValidatingWebhookConfiguration
...
webhooks :
- name : my-webhook.example.com
matchPolicy : Equivalent
rules :
- operations : ["CREATE" ,"UPDATE" ,"DELETE" ]
apiGroups : ["apps" ]
apiVersions : ["v1" ]
resources : ["deployments" ]
scope : "Namespaced"
...
使用 admissionregistration.k8s.io/v1 创建的 admission webhhok 默认为 Equivalent。
# v1.16 中被废弃,推荐使用 admissionregistration.k8s.io/v1
apiVersion : admissionregistration.k8s.io/v1beta1
kind : ValidatingWebhookConfiguration
...
webhooks :
- name : my-webhook.example.com
matchPolicy : Equivalent
rules :
- operations : ["CREATE" ,"UPDATE" ,"DELETE" ]
apiGroups : ["apps" ]
apiVersions : ["v1" ]
resources : ["deployments" ]
scope : "Namespaced"
...
使用 admissionregistration.k8s.io/v1beta1 创建的准入 Webhook 默认为 Exact。
调用 Webhook API 服务器确定请求应发送到 webhook 后,它需要知道如何调用 webhook。
此信息在 webhook 配置的 clientConfig 节中指定。
Webhook 可以通过 URL 或服务引用来调用,并且可以选择包含自定义 CA 包,以用于验证 TLS 连接。
URL url 以标准 URL 形式给出 webhook 的位置(scheme://host:port/path)。
host 不应引用集群中运行的服务;通过指定 service 字段来使用服务引用。
主机可以通过某些 apiserver 中的外部 DNS 进行解析。
(例如,kube-apiserver 无法解析集群内 DNS,因为这将违反分层规则)。host 也可以是 IP 地址。
请注意,将 localhost 或 127.0.0.1 用作 host 是有风险的,
除非你非常小心地在所有运行 apiserver 的、可能需要对此 webhook
进行调用的主机上运行。这样的安装可能不具有可移植性,即很难在新集群中启用。
scheme 必须为 "https";URL 必须以 "https://" 开头。
使用用户或基本身份验证(例如:"user:password@")是不允许的。
使用片段("#...")和查询参数("?...")也是不允许的。
这是配置为调用 URL 的修改性质的 Webhook 的示例
(并且期望使用系统信任根证书来验证 TLS 证书,因此不指定 caBundle):
apiVersion : admissionregistration.k8s.io/v1
kind : MutatingWebhookConfiguration
...
webhooks :
- name : my-webhook.example.com
clientConfig :
url : "https://my-webhook.example.com:9443/my-webhook-path"
...
# v1.16 中被废弃,推荐使用 admissionregistration.k8s.io/v1
apiVersion : admissionregistration.k8s.io/v1beta1
kind : MutatingWebhookConfiguration
...
webhooks :
- name : my-webhook.example.com
clientConfig :
url : "https://my-webhook.example.com:9443/my-webhook-path"
...
服务引用 clientConfig 内部的 Service 是对该 Webhook 服务的引用。
如果 Webhook 在集群中运行,则应使用 service 而不是 url。
服务的 namespace 和 name 是必需的。
port 是可选的,默认值为 443。path 是可选的,默认为 "/"。
这是一个 mutating Webhook 的示例,该 mutating Webhook 配置为在子路径 "/my-path" 端口
"1234" 上调用服务,并使用自定义 CA 包针对 ServerName
my-service-name.my-service-namespace.svc 验证 TLS 连接:
apiVersion : admissionregistration.k8s.io/v1
kind : MutatingWebhookConfiguration
...
webhooks :
- name : my-webhook.example.com
clientConfig :
caBundle : "Ci0tLS0tQk...<base64-encoded PEM bundle containing the CA that signed the webhook's serving certificate>...tLS0K"
service :
namespace : my-service-namespace
name : my-service-name
path : /my-path
port : 1234
...
# v1.16 中被废弃,推荐使用 admissionregistration.k8s.io/v1
apiVersion : admissionregistration.k8s.io/v1beta1
kind : MutatingWebhookConfiguration
...
webhooks :
- name : my-webhook.example.com
clientConfig :
caBundle : "Ci0tLS0tQk...<base64-encoded PEM bundle containing the CA that signed the webhook's serving certificate>...tLS0K"
service :
namespace : my-service-namespace
name : my-service-name
path : /my-path
port : 1234
...
副作用 Webhook 通常仅对发送给他们的 AdmissionReview 内容进行操作。
但是,某些 Webhook 在处理 admission 请求时会进行带外更改。
进行带外更改的(产生“副作用”的) Webhook 必须具有协调机制(如控制器),
该机制定期确定事物的实际状态,并调整由准入 Webhook 修改的带外数据以反映现实情况。
这是因为对准入 Webhook 的调用不能保证所准入的对象将原样保留,或根本不保留。
以后,webhook 可以修改对象的内容,在写入存储时可能会发生冲突,或者
服务器可以在持久保存对象之前关闭电源。
此外,处理 dryRun: true admission 请求时,具有副作用的 Webhook 必须避免产生副作用。
一个 Webhook 必须明确指出在使用 dryRun 运行时不会有副作用,
否则 dry-run 请求将不会发送到该 Webhook,而 API 请求将会失败。
Webhook 使用 webhook 配置中的 sideEffects 字段显示它们是否有副作用:
Unknown:有关调用 Webhook 的副作用的信息是不可知的。
如果带有 dryRun:true 的请求将触发对该 Webhook 的调用,则该请求将失败,并且不会调用该 Webhook。None:调用 webhook 没有副作用。Some:调用 webhook 可能会有副作用。
如果请求具有 dry-run 属性将触发对此 Webhook 的调用,
则该请求将会失败,并且不会调用该 Webhook。NoneOnDryRun:调用 webhook 可能会有副作用,但是如果将带有 dryRun: true
属性的请求发送到 webhook,则 webhook 将抑制副作用(该 webhook 可识别 dryRun)。允许值:
在 admissionregistration.k8s.io/v1beta1 中,sideEffects 可以设置为
Unknown、None、Some 或者 NoneOnDryRun,并且默认值为 Unknown。 在 admissionregistration.k8s.io/v1 中, sideEffects 必须设置为
None 或者 NoneOnDryRun。 这是一个 validating webhook 的示例,表明它对 dryRun: true 请求没有副作用:
apiVersion : admissionregistration.k8s.io/v1
kind : ValidatingWebhookConfiguration
...
webhooks :
- name : my-webhook.example.com
sideEffects : NoneOnDryRun
...
# v1.16 中被废弃,推荐使用 admissionregistration.k8s.io/v1
apiVersion : admissionregistration.k8s.io/v1beta1
kind : ValidatingWebhookConfiguration
...
webhooks :
- name : my-webhook.example.com
sideEffects : NoneOnDryRun
...
超时 由于 Webhook 会增加 API 请求的延迟,因此应尽快完成自身的操作。
timeoutSeconds 用来配置在将调用视为失败之前,允许 API 服务器等待 Webhook 响应的时间长度。
如果超时在 Webhook 响应之前被触发,则基于失败策略 ,将忽略
Webhook 调用或拒绝 API 调用。
超时值必须设置在 1 到 30 秒之间。
这是一个自定义超时设置为 2 秒的 validating Webhook 的示例:
apiVersion : admissionregistration.k8s.io/v1
kind : ValidatingWebhookConfiguration
...
webhooks :
- name : my-webhook.example.com
timeoutSeconds : 2
...
使用 admissionregistration.k8s.io/v1 创建的准入 Webhook 默认超时为 10 秒。
# v1.16 中被废弃,推荐使用 admissionregistration.k8s.io/v1
apiVersion : admissionregistration.k8s.io/v1beta1
kind : ValidatingWebhookConfiguration
...
webhooks :
- name : my-webhook.example.com
timeoutSeconds : 2
...
使用 admissionregistration.k8s.io/v1beta1 创建的准入 Webhook 默认超时为 30 秒。
再调用策略 修改性质的准入插件(包括 Webhook)的任何一种排序方式都不会适用于所有情况。
(参见 https://issue.k8s.io/64333 示例)。
修改性质的 Webhook 可以向对象中添加新的子结构(例如向 pod 中添加 container),
已经运行的其他修改插件可能会对这些新结构有影响
(就像在所有容器上设置 imagePullPolicy 一样)。
在 v1.15+ 中,允许修改性质的准入插件感应到其他插件所做的更改,
如果修改性质的 Webhook 修改了一个对象,则会重新运行内置的修改性质的准入插件,
并且修改性质的 Webhook 可以指定 reinvocationPolicy 来控制是否也重新调用它们。
可以将 reinvocationPolicy 设置为 Never 或 IfNeeded。 默认为 Never。
Never: 在一次准入测试中,不得多次调用 Webhook。IfNeeded: 如果在最初的 Webhook 调用之后被其他对象的插件修改了被接纳的对象,
则可以作为准入测试的一部分再次调用该 webhook。要注意的重要因素有:
不能保证附加调用的次数恰好是一。 如果其他调用导致对该对象的进一步修改,则不能保证再次调用 Webhook。 使用此选项的 Webhook 可能会重新排序,以最大程度地减少额外调用的次数。 要在确保所有修改都完成后验证对象,请改用验证性质的 Webhook
(推荐用于有副作用的 Webhook)。 这是一个修改性质的 Webhook 的示例,该 Webhook 在以后的准入插件修改对象时被重新调用:
apiVersion : admissionregistration.k8s.io/v1
kind : MutatingWebhookConfiguration
...
webhooks :
- name : my-webhook.example.com
reinvocationPolicy : IfNeeded
...
# v1.16 中被废弃,推荐使用 admissionregistration.k8s.io/v1
apiVersion : admissionregistration.k8s.io/v1beta1
kind : MutatingWebhookConfiguration
...
webhooks :
- name : my-webhook.example.com
reinvocationPolicy : IfNeeded
...
修改性质的 Webhook 必须具有幂等 性,并且能够成功处理
已被接纳并可能被修改的对象的修改性质的 Webhook。
对于所有修改性质的准入 Webhook 都是如此,因为它们可以在对象中进行的
任何更改可能已经存在于用户提供的对象中,但是对于选择重新调用的 webhook
来说是必不可少的。
失败策略 failurePolicy 定义了如何处理准入 webhook 中无法识别的错误和超时错误。允许的值为 Ignore 或 Fail。
Ignore 表示调用 webhook 的错误将被忽略并且允许 API 请求继续。Fail 表示调用 webhook 的错误导致准入失败并且 API 请求被拒绝。这是一个修改性质的 webhook,配置为在调用准入 Webhook 遇到错误时拒绝 API 请求:
apiVersion : admissionregistration.k8s.io/v1
kind : MutatingWebhookConfiguration
...
webhooks :
- name : my-webhook.example.com
failurePolicy : Fail
...
使用 admissionregistration.k8s.io/v1beta1 创建的准入 Webhook 将
failurePolicy 默认设置为 Ignore。
# v1.16 中被废弃,推荐使用 admissionregistration.k8s.io/v1
apiVersion : admissionregistration.k8s.io/v1beta1
kind : MutatingWebhookConfiguration
...
webhooks :
- name : my-webhook.example.com
failurePolicy : Fail
...
使用 admissionregistration.k8s.io/v1beta1 创建的准入 Webhook 将
failurePolicy 默认设置为 Ignore。
监控 Admission Webhook API 服务器提供了监视准入 Webhook 行为的方法。这些监视机制可帮助集群管理员
回答以下问题:
哪个修改性质的 webhook 改变了 API 请求中的对象? 修改性质的 Webhook 对对象做了哪些更改? 哪些 webhook 经常拒绝 API 请求?是什么原因拒绝? Mutating Webhook 审计注解 有时,了解 API 请求中的哪个修改性质的 Webhook 使对象改变以及该
Webhook 应用了哪些更改很有用。
在 v1.16+ 中,kube-apiserver 针对每个修改性质的 Webhook 调用执行
审计 操作。
每个调用都会生成一个审计注解,记述请求对象是否发生改变,
可选地还可以根据 webhook 的准入响应生成一个注解,记述所应用的修补。
针对给定请求的给定执行阶段,注解被添加到审计事件中,
然后根据特定策略进行预处理并写入后端。
事件的审计级别决定了要记录哪些注解:
在 Metadata 或更高审计级别上,将使用 JSON 负载记录带有键名
mutation.webhook.admission.k8s.io/round_{round idx}_index_{order idx} 的注解,
该注解表示针对给定请求调用了 Webhook,以及该 Webhook 是否更改了对象。
例如,对于正在被重新调用的某 Webhook,所记录的注解如下。
Webhook 在 mutating Webhook 链中排在第三个位置,并且在调用期间未改变请求对象。
# 审计事件相关记录
{
"kind": "Event" ,
"apiVersion": "audit.k8s.io/v1" ,
"annotations": {
"mutation.webhook.admission.k8s.io/round_1_index_2": "{\"configuration\":\"my-mutating-webhook-configuration.example.com\",\"webhook\":\"my-webhook.example.com\",\"mutated\": false }"
# 其他注解
...
}
# 其他字段
...
}
# 反序列化的注解值
{
"configuration": "my-mutating-webhook-configuration.example.com" ,
"webhook": "my-webhook.example.com" ,
"mutated": false
}
对于在第一轮中调用的 Webhook,所记录的注解如下。
Webhook 在 mutating Webhook 链中排在第一位,并在调用期间改变了请求对象。
# 审计事件相关记录
{
"kind": "Event" ,
"apiVersion": "audit.k8s.io/v1" ,
"annotations": {
"mutation.webhook.admission.k8s.io/round_0_index_0": "{\"configuration\":\"my-mutating-webhook-configuration.example.com\",\"webhook\":\"my-webhook-always-mutate.example.com\",\"mutated\": true }"
# 其他注解
...
}
# 其他字段
...
}
# 反序列化的注解值
{
"configuration": "my-mutating-webhook-configuration.example.com" ,
"webhook": "my-webhook-always-mutate.example.com" ,
"mutated": true
}
在 Request 或更高审计级别上,将使用 JSON 负载记录带有键名为
patch.webhook.admission.k8s.io/round_{round idx}_index_{order idx} 的注解,
该注解表明针对给定请求调用了 Webhook 以及应用于请求对象之上的修改。
例如,以下是针对正在被重新调用的某 Webhook 所记录的注解。
Webhook 在修改性质的 Webhook 链中排在第四,并在其响应中包含一个 JSON 补丁,
该补丁已被应用于请求对象。
# 审计事件相关记录
{
"kind": "Event" ,
"apiVersion": "audit.k8s.io/v1" ,
"annotations": {
"patch.webhook.admission.k8s.io/round_1_index_3": "{\"configuration\":\"my-other-mutating-webhook-configuration.example.com\",\"webhook\":\"my-webhook-always-mutate.example.com\",\"patch\":[{\"op\":\"add\",\"path\":\"/data/mutation-stage\",\"value\":\"yes\"}],\"patchType\":\"JSONPatch\"}"
# 其他注解
...
}
# 其他字段
...
}
# 反序列化的注解值
{
"configuration": "my-other-mutating-webhook-configuration.example.com" ,
"webhook": "my-webhook-always-mutate.example.com" ,
"patchType": "JSONPatch" ,
"patch": [
{
"op": "add" ,
"path": "/data/mutation-stage" ,
"value": "yes"
}
]
}
准入 Webhook 度量值 Kube-apiserver 从 /metrics 端点公开 Prometheus 指标,这些指标可用于监控和诊断
apiserver 状态。以下指标记录了与准入 Webhook 相关的状态。
apiserver 准入 Webhook 拒绝次数 有时,了解哪些准入 Webhook 经常拒绝 API 请求以及拒绝的原因是很有用的。
在 v1.16+ 中,kube-apiserver 提供了 Prometheus 计数器度量值,记录
准入 Webhook 的拒绝次数。
度量值的标签给出了 Webhook 拒绝该请求的原因:
name:拒绝请求 Webhook 的名称。operation:请求的操作类型可以是 CREATE、UPDATE、DELETE 和 CONNECT 其中之一。type:Admission webhook 类型,可以是 admit 和 validating 其中之一。error_type:标识在 webhook 调用期间是否发生了错误并且导致了拒绝。其值可以是以下之一:calling_webhook_error:发生了来自准入 Webhook 的无法识别的错误或超时错误,
并且 webhook 的 失败策略 设置为 Fail。no_error:未发生错误。Webhook 在准入响应中以 allowed: false 值拒绝了请求。
度量标签 rejection_code 记录了在准入响应中设置的 .status.code。apiserver_internal_error:apiserver 发生内部错误。rejection_code:当 Webhook 拒绝请求时,在准入响应中设置的 HTTP 状态码。拒绝计数指标示例:
# HELP apiserver_admission_webhook_rejection_count [ALPHA] Admission webhook rejection count, identified by name and broken out for each admission type (validating or admit) and operation. Additional labels specify an error type (calling_webhook_error or apiserver_internal_error if an error occurred; no_error otherwise) and optionally a non-zero rejection code if the webhook rejects the request with an HTTP status code (honored by the apiserver when the code is greater or equal to 400). Codes greater than 600 are truncated to 600, to keep the metrics cardinality bounded.
# TYPE apiserver_admission_webhook_rejection_count counter
apiserver_admission_webhook_rejection_count{error_type="calling_webhook_error",name="always-timeout-webhook.example.com",operation="CREATE",rejection_code="0",type="validating"} 1
apiserver_admission_webhook_rejection_count{error_type="calling_webhook_error",name="invalid-admission-response-webhook.example.com",operation="CREATE",rejection_code="0",type="validating"} 1
apiserver_admission_webhook_rejection_count{error_type="no_error",name="deny-unwanted-configmap-data.example.com",operation="CREATE",rejection_code="400",type="validating"} 13
最佳实践和警告 幂等性 幂等的修改性质的准入 Webhook 能够成功处理已经被它接纳甚或修改的对象。
即使多次执行该准入测试,也不会产生与初次执行结果相异的结果。
幂等 mutating admission Webhook 的示例: 对于 CREATE Pod 请求,将 Pod 的字段 .spec.securityContext.runAsNonRoot
设置为 true,以实施安全最佳实践。 对于 CREATE Pod 请求,如果未设置容器的字段
.spec.containers[].resources.limits,设置默认资源限制值。 对于 CREATE pod 请求,如果 Pod 中不存在名为 foo-sidecar 的边车容器,
向 Pod 注入一个 foo-sidecar 容器。 在上述情况下,可以安全地重新调用 Webhook,或接受已经设置了字段的对象。
非幂等 mutating admission Webhook 的示例: 对于 CREATE pod 请求,注入名称为 foo-sidecar 并带有当前时间戳的
边车容器(例如 foo-sidecar-19700101-000000)。 对于 CREATE/UPDATE pod 请求,如果容器已设置标签 "env" 则拒绝,
否则将 "env": "prod" 标签添加到容器。 对于 CREATE pod 请求,盲目地添加一个名为 foo-sidecar 的边车容器,
而未查看 Pod 中是否已经有 foo-sidecar 容器。 在上述第一种情况下,重新调用该 Webhook 可能导致同一个 Sidecar 容器
多次注入到 Pod 中,而且每次使用不同的容器名称。
类似地,如果 Sidecar 已存在于用户提供的 Pod 中,则 Webhook 可能注入重复的容器。
在上述第二种情况下,重新调用 Webhook 将导致 Webhook 自身输出失败。
在上述第三种情况下,重新调用 Webhook 将导致 Pod 规范中的容器重复,
从而使请求无效并被 API 服务器拒绝。
拦截对象的所有版本 建议通过将 .webhooks[].matchPolicy 设置为 Equivalent,
以确保准入 Webhooks 始终拦截对象的所有版本。
建议准入 Webhooks 应该更偏向注册资源的稳定版本。
如果无法拦截对象的所有版本,可能会导致准入策略未再某些版本的请求上执行。
有关示例,请参见匹配请求:matchPolicy 。
可用性 建议准入 webhook 尽快完成执行(时长通常是毫秒级),因为它们会增加 API 请求的延迟。
建议对 Webhook 使用较小的超时值。有关更多详细信息,请参见超时 。
建议 Admission Webhook 应该采用某种形式的负载均衡机制,以提供高可用性和高性能。
如果集群中正在运行 Webhook,则可以在服务后面运行多个 Webhook 后端,以利用该服务支持的负载均衡。
确保看到对象的最终状态 如果某准入 Webhook 需要保证自己能够看到对象的最终状态以实施策略,
则应该使用一个验证性质的 webhook,
因为可以通过 mutating Webhook 看到对象后对其进行修改。
例如,一个修改性质的准入Webhook 被配置为在每个 CREATE Pod 请求中
注入一个名称为 "foo-sidecar" 的 sidecar 容器。
如果必须 存在边车容器,则还应配置一个验证性质的准入 Webhook 以拦截
CREATE Pod 请求,并验证要创建的对象中是否存在具有预期配置的名称为
"foo-sidecar" 的容器。
避免自托管的 Webhooks 中出现死锁 如果集群内的 Webhook 配置能够拦截启动其自己的 Pod 所需的资源,
则该 Webhook 可能导致其自身部署时发生死锁。
例如,某修改性质的准入 Webhook 配置为仅当 Pod 中设置了某个标签
(例如 "env": "prod")时,才接受 CREATE Pod 请求。
Webhook 服务器在未设置 "env" 标签的 Deployment 中运行。当运行 Webhook 服务器的
容器的节点运行不正常时,Webhook 部署尝试将容器重新调度到另一个节点。
但是,由于未设置 "env" 标签,因此请求将被现有的 Webhook 服务器拒绝,并且调度迁移不会发生。
建议使用 namespaceSelector 排除
Webhook 所在的名字空间。
副作用 建议准入 Webhook 应尽可能避免副作用,这意味着该准入 webhook 仅对发送给他们的
AdmissionReview 的内容起作用,并且不要进行额外更改。
如果 Webhook 没有任何副作用,则 .webhooks[].sideEffects 字段应设置为
None。
如果在准入执行期间存在副作用,则应在处理 dryRun 为 true 的 AdmissionReview
对象时避免产生副作用,并且其 .webhooks[].sideEffects 字段应设置为
NoneOnDryRun。更多详细信息,请参见副作用 。
避免对 kube-system 名字空间进行操作 kube-system 名字空间包含由 Kubernetes 系统创建的对象,
例如用于控制平面组件的服务账号,诸如 kube-dns 之类的 Pod 等。
意外更改或拒绝 kube-system 名字空间中的请求可能会导致控制平面组件
停止运行或者导致未知行为发生。
如果你的准入 Webhook 不想修改 Kubernetes 控制平面的行为,请使用
namespaceSelector 避免
拦截 kube-system 名字空间。
6.5.6 - 管理 Service Accounts 这是一篇针对服务账号的集群管理员指南。你应该熟悉
配置 Kubernetes 服务账号 。
对鉴权和用户账号的支持已在规划中,当前并不完备。
为了更好地描述服务账号,有时这些不完善的特性也会被提及。
用户账号与服务账号 Kubernetes 区分用户账号和服务账号的概念,主要基于以下原因:
用户账号是针对人而言的。 服务账号是针对运行在 Pod 中的进程而言的。 用户账号是全局性的。其名称跨集群中名字空间唯一的。服务账号是名字空间作用域的。 通常情况下,集群的用户账号可能会从企业数据库进行同步,其创建需要特殊权限,
并且涉及到复杂的业务流程。
服务账号创建有意做得更轻量,允许集群用户为了具体的任务创建服务账号
以遵从权限最小化原则。 对人员和服务账号审计所考虑的因素可能不同。 针对复杂系统的配置包可能包含系统组件相关的各种服务账号的定义。因为服务账号
的创建约束不多并且有名字空间域的名称,这种配置是很轻量的。 服务账号的自动化 三个独立组件协作完成服务账号相关的自动化:
ServiceAccount 准入控制器Token 控制器 ServiceAccount 控制器ServiceAccount 准入控制器 对 Pod 的改动通过一个被称为
准入控制器
的插件来实现。它是 API 服务器的一部分。
当 Pod 被创建或更新时,它会同步地修改 Pod。
如果该插件处于激活状态(在大多数发行版中都是默认激活的),当 Pod 被创建
或更新时它会进行以下操作:
如果该 Pod 没有设置 serviceAccountName,将其 serviceAccountName 设为
default。 保证 Pod 所引用的 serviceAccountName 确实存在,否则拒绝该 Pod。 如果 Pod 不包含 imagePullSecrets 设置,将 serviceAccountName 所引用
的服务账号中的 imagePullSecrets 信息添加到 Pod 中。 如果服务账号的 automountServiceAccountToken 或 Pod 的
automountServiceAccountToken 都为设置为 false,则为 Pod 创建一个
volume,在其中包含用来访问 API 的令牌。 如果前一步中为服务账号令牌创建了卷,则为 Pod 中的每个容器添加一个
volumeSource,挂载在其 /var/run/secrets/kubernetes.io/serviceaccount
目录下。 当 BoundServiceAccountTokenVolume 特性门控被启用时,你可以将服务账号卷迁移到投射卷。
服务账号令牌会在 1 小时后或者 Pod 被删除之后过期。
更多信息可参阅投射卷 。
Token 控制器 TokenController 作为 kube-controller-manager 的一部分运行,以异步的形式工作。
其职责包括:
监测 ServiceAccount 的创建并创建相应的服务账号令牌 Secret 以允许访问 API。 监测 ServiceAccount 的删除并删除所有相应的服务账号令牌 Secret。 监测服务账号令牌 Secret 的添加,保证相应的 ServiceAccount 存在,如有需要,
向 Secret 中添加令牌。 监测服务账号令牌 Secret 的删除,如有需要,从相应的 ServiceAccount 中移除引用。 你必须通过 --service-account-private-key-file 标志为 kube-controller-manager
的令牌控制器传入一个服务账号私钥文件。该私钥用于为所生成的服务账号令牌签名。
同样地,你需要通过 --service-account-key-file 标志将对应的公钥通知给
kube-apiserver。公钥用于在身份认证过程中校验令牌。
创建额外的 API 令牌 控制器中有专门的循环来保证每个 ServiceAccount 都存在对应的包含 API 令牌的 Secret。
当需要为 ServiceAccount 创建额外的 API 令牌时,可以创建一个类型为
kubernetes.io/service-account-token 的 Secret,并在其注解中引用对应的
ServiceAccount。控制器会生成令牌并更新该 Secret:
下面是这种 Secret 的一个示例配置:
apiVersion : v1
kind : Secret
metadata :
name : mysecretname
annotations :
kubernetes.io/service-account.name : myserviceaccount
type : kubernetes.io/service-account-token
kubectl create -f ./secret.json
kubectl describe secret mysecretname
删除/废止服务账号令牌 Secret kubectl delete secret mysecretname
服务账号控制器 服务账号控制器管理各名字空间下的 ServiceAccount 对象,并且保证每个活跃的
名字空间下存在一个名为 "default" 的 ServiceAccount。
6.5.7 - 鉴权概述 了解有关 Kubernetes 鉴权的更多信息,包括使用支持的鉴权模块创建策略的详细信息。
在 Kubernetes 中,你必须在鉴权(授予访问权限)之前进行身份验证(登录),有关身份验证的信息,
请参阅访问控制概述 .
Kubernetes 期望请求中存在 REST API 常见的属性。
这意味着 Kubernetes 鉴权适用于现有的组织范围或云提供商范围的访问控制系统,
除了 Kubernetes API 之外,它还可以处理其他 API。
确定是允许还是拒绝请求 Kubernetes 使用 API 服务器对 API 请求进行鉴权。
它根据所有策略评估所有请求属性来决定允许或拒绝请求。
一个 API 请求的所有部分都必须被某些策略允许才能继续。
这意味着默认情况下拒绝权限。
(尽管 Kubernetes 使用 API 服务器,但是依赖于特定对象种类的特定字段的访问控制
和策略由准入控制器处理。)
当系统配置了多个鉴权模块时,Kubernetes 将按顺序使用每个模块。
如果任何鉴权模块批准或拒绝请求,则立即返回该决定,并且不会与其他鉴权模块协商。
如果所有模块对请求没有意见,则拒绝该请求。
被拒绝响应返回 HTTP 状态代码 403。
审查你的请求属性 Kubernetes 仅审查以下 API 请求属性:
用户 - 身份验证期间提供的 user 字符串。组 - 经过身份验证的用户所属的组名列表。额外信息 - 由身份验证层提供的任意字符串键到字符串值的映射。API - 指示请求是否针对 API 资源。请求路径 - 各种非资源端点的路径,如 /api 或 /healthz。API 请求动词 - API 动词 get、list、create、update、patch、watch、
proxy、redirect、delete 和 deletecollection 用于资源请求。
要确定资源 API 端点的请求动词,请参阅
确定请求动词 。HTTP 请求动词 - HTTP 动词 get、post、put 和 delete 用于非资源请求。Resource - 正在访问的资源的 ID 或名称(仅限资源请求)-
对于使用 get、update、patch 和 delete 动词的资源请求,你必须提供资源名称。子资源 - 正在访问的子资源(仅限资源请求)。名字空间 - 正在访问的对象的名称空间(仅适用于名字空间资源请求)。API 组 - 正在访问的 API 组
(仅限资源请求)。空字符串表示核心 API 组 。确定请求动词 非资源请求
对于 /api/v1/... 或 /apis/<group>/<version>/... 之外的端点的请求被
视为“非资源请求(Non-Resource Requests)”,并使用该请求的 HTTP 方法的
小写形式作为其请求动词。
例如,对 /api 或 /healthz 这类端点的 GET 请求将使用 get 作为其动词。
资源请求
要确定对资源 API 端点的请求动词,需要查看所使用的 HTTP 动词以及该请求是针对
单个资源还是一组资源:
HTTP 动词 请求动词 POST create GET, HEAD get (针对单个资源)、list(针对集合) PUT update PATCH patch DELETE delete(针对单个资源)、deletecollection(针对集合)
Kubernetes 有时使用专门的动词以对额外的权限进行鉴权。例如:
PodSecurityPolicy policy API 组中 podsecuritypolicies 资源使用 use 动词RBAC 对 rbac.authorization.k8s.io API 组中 roles 和 clusterroles 资源的 bind
和 escalate 动词 身份认证 对核心 API 组中 users、groups 和 serviceaccounts 以及 authentication.k8s.io
API 组中的 userextras 所使用的 impersonate 动词。 鉴权模块 Node - 一个专用鉴权组件,根据调度到 kubelet 上运行的 Pod 为 kubelet 授予权限。
了解有关使用节点鉴权模式的更多信息,请参阅节点鉴权 。ABAC - 基于属性的访问控制(ABAC)定义了一种访问控制范型,通过使用将属性组合
在一起的策略,将访问权限授予用户。策略可以使用任何类型的属性(用户属性、资源属性、
对象,环境属性等)。要了解有关使用 ABAC 模式的更多信息,请参阅
ABAC 模式 。RBAC - 基于角色的访问控制(RBAC)是一种基于企业内个人用户的角色来管理对
计算机或网络资源的访问的方法。在此上下文中,权限是单个用户执行特定任务的能力,
例如查看、创建或修改文件。要了解有关使用 RBAC 模式的更多信息,请参阅
RBAC 模式 。被启用之后,RBAC(基于角色的访问控制)使用 rbac.authorization.k8s.io API 组来
驱动鉴权决策,从而允许管理员通过 Kubernetes API 动态配置权限策略。 要启用 RBAC,请使用 --authorization-mode = RBAC 启动 API 服务器。 Webhook - WebHook 是一个 HTTP 回调:发生某些事情时调用的 HTTP POST;
通过 HTTP POST 进行简单的事件通知。实现 WebHook 的 Web 应用程序会在发生某些事情时
将消息发布到 URL。要了解有关使用 Webhook 模式的更多信息,请参阅
Webhook 模式 。检查 API 访问 kubectl 提供 auth can-i 子命令,用于快速查询 API 鉴权。
该命令使用 SelfSubjectAccessReview API 来确定当前用户是否可以执行给定操作,
无论使用何种鉴权模式该命令都可以工作。
kubectl auth can-i create deployments --namespace dev
yes
kubectl auth can-i create deployments --namespace prod
no
管理员可以将此与
用户扮演
结合使用,以确定其他用户可以执行的操作。
kubectl auth can-i list secrets --namespace dev --as dave
no
SelfSubjectAccessReview 是 authorization.k8s.io API 组的一部分,它将 API
服务器鉴权公开给外部服务。该组中的其他资源包括:
SubjectAccessReview - 对任意用户的访问进行评估,而不仅仅是当前用户。
当鉴权决策被委派给 API 服务器时很有用。例如,kubelet 和扩展 API 服务器使用
它来确定用户对自己的 API 的访问权限。LocalSubjectAccessReview - 与 SubjectAccessReview 类似,但仅限于特定的
名字空间。SelfSubjectRulesReview - 返回用户可在名字空间内执行的操作集的审阅。
用户可以快速汇总自己的访问权限,或者用于 UI 中的隐藏/显示动作。可以通过创建普通的 Kubernetes 资源来查询这些 API,其中返回对象的响应 "status"
字段是查询的结果。
kubectl create -f - -o yaml << EOF
apiVersion: authorization.k8s.io/v1
kind: SelfSubjectAccessReview
spec:
resourceAttributes:
group: apps
name: deployments
verb: create
namespace: dev
EOF
生成的 SelfSubjectAccessReview 为:
apiVersion : authorization.k8s.io/v1
kind : SelfSubjectAccessReview
metadata :
creationTimestamp : null
spec :
resourceAttributes :
group : apps
name : deployments
namespace : dev
verb : create
status :
allowed : true
denied : false
为你的鉴权模块设置参数 你必须在策略中包含一个参数标志,以指明你的策略包含哪个鉴权模块:
可以使用的参数有:
--authorization-mode=ABAC 基于属性的访问控制(ABAC)模式允许你
使用本地文件配置策略。--authorization-mode=RBAC 基于角色的访问控制(RBAC)模式允许你使用
Kubernetes API 创建和存储策略。--authorization-mode=Webhook WebHook 是一种 HTTP 回调模式,允许你使用远程
REST 端点管理鉴权。--authorization-mode=Node 节点鉴权是一种特殊用途的鉴权模式,专门对
kubelet 发出的 API 请求执行鉴权。--authorization-mode=AlwaysDeny 该标志阻止所有请求。仅将此标志用于测试。--authorization-mode=AlwaysAllow 此标志允许所有请求。仅在你不需要 API 请求
的鉴权时才使用此标志。你可以选择多个鉴权模块。模块按顺序检查,以便较靠前的模块具有更高的优先级来允许
或拒绝请求。
通过创建 Pod 提升权限 能够在名字空间中创建 Pod 的用户可能会提升其在该名字空间内的权限。
他们可以创建在该名字空间内访问其权限的 Pod。
他们可以创建 Pod 访问用户自己无法读取的 Secret,或者在具有不同/更高权限的
服务帐户下运行的 Pod 。
注意: 系统管理员在授予对 Pod 创建的访问权限时要小心。
被授予在名字空间中创建 Pod(或创建 Pod 的控制器)的权限的用户可以:
读取名字空间中的所有 Secret;读取名字空间中的所有 ConfigMap;
并模拟名字空间中的任意服务账号并执行账号可以执行的任何操作。
无论采用何种鉴权方式,这都适用。
接下来 6.5.8 - 使用 RBAC 鉴权 基于角色(Role)的访问控制(RBAC)是一种基于组织中用户的角色来调节控制对
计算机或网络资源的访问的方法。
RBAC 鉴权机制使用 rbac.authorization.k8s.io
API 组
来驱动鉴权决定,允许你通过 Kubernetes API 动态配置策略。
要启用 RBAC,在启动 API 服务器
时将 --authorization-mode 参数设置为一个逗号分隔的列表并确保其中包含 RBAC。
kube-apiserver --authorization-mode= Example,RBAC --<其他选项> --<其他选项>
API 对象 RBAC API 声明了四种 Kubernetes 对象:Role 、ClusterRole 、RoleBinding 和
ClusterRoleBinding 。你可以像使用其他 Kubernetes 对象一样,
通过类似 kubectl 这类工具
描述对象 ,
或修补对象。
注意: 这些对象在设计时即实施了一些访问限制。如果你在学习过程中对集群做了更改,请参考
避免特权提升和引导
一节,以了解这些限制会以怎样的方式阻止你做出修改。
Role 和 ClusterRole RBAC 的 Role 或 ClusterRole 中包含一组代表相关权限的规则。
这些权限是纯粹累加的(不存在拒绝某操作的规则)。
Role 总是用来在某个名字空间
内设置访问权限;在你创建 Role 时,你必须指定该 Role 所属的名字空间。
与之相对,ClusterRole 则是一个集群作用域的资源。这两种资源的名字不同(Role 和
ClusterRole)是因为 Kubernetes 对象要么是名字空间作用域的,要么是集群作用域的,
不可两者兼具。
ClusterRole 有若干用法。你可以用它来:
定义对某名字空间域对象的访问权限,并将在各个名字空间内完成授权; 为名字空间作用域的对象设置访问权限,并跨所有名字空间执行授权; 为集群作用域的资源定义访问权限。 如果你希望在名字空间内定义角色,应该使用 Role;
如果你希望定义集群范围的角色,应该使用 ClusterRole。
Role 示例 下面是一个位于 "default" 名字空间的 Role 的示例,可用来授予对
pods 的读访问权限:
apiVersion : rbac.authorization.k8s.io/v1
kind : Role
metadata :
namespace : default
name : pod-reader
rules :
- apiGroups : ["" ] # "" 标明 core API 组
resources : ["pods" ]
verbs : ["get" , "watch" , "list" ]
ClusterRole 示例 ClusterRole 可以和 Role 相同完成授权。
因为 ClusterRole 属于集群范围,所以它也可以为以下资源授予访问权限:
集群范围资源(比如 节点(Node) ) 非资源端点(比如 /healthz) 跨名字空间访问的名字空间作用域的资源(如 Pods),比如,你可以使用
ClusterRole 来允许某特定用户执行 kubectl get pods --all-namespaces 下面是一个 ClusterRole 的示例,可用来为任一特定名字空间中的
Secret 授予读访问权限,
或者跨名字空间的访问权限(取决于该角色是如何绑定 的):
apiVersion : rbac.authorization.k8s.io/v1
kind : ClusterRole
metadata :
# "namespace" 被忽略,因为 ClusterRoles 不受名字空间限制
name : secret-reader
rules :
- apiGroups : ["" ]
# 在 HTTP 层面,用来访问 Secret 对象的资源的名称为 "secrets"
resources : ["secrets" ]
verbs : ["get" , "watch" , "list" ]
Role 或 ClusterRole 对象的名称必须是合法的
路径区段名称 。
RoleBinding 和 ClusterRoleBinding 角色绑定(Role Binding)是将角色中定义的权限赋予一个或者一组用户。
它包含若干 主体 (用户、组或服务账户)的列表和对这些主体所获得的角色的引用。
RoleBinding 在指定的名字空间中执行授权,而 ClusterRoleBinding 在集群范围执行授权。
一个 RoleBinding 可以引用同一的名字空间中的任何 Role。
或者,一个 RoleBinding 可以引用某 ClusterRole 并将该 ClusterRole 绑定到
RoleBinding 所在的名字空间。
如果你希望将某 ClusterRole 绑定到集群中所有名字空间,你要使用 ClusterRoleBinding。
RoleBinding 或 ClusterRoleBinding 对象的名称必须是合法的
路径区段名称 。
RoleBinding 示例 下面的例子中的 RoleBinding 将 "pod-reader" Role 授予在 "default" 名字空间中的用户 "jane"。
这样,用户 "jane" 就具有了读取 "default" 名字空间中 pods 的权限。
apiVersion : rbac.authorization.k8s.io/v1
# 此角色绑定允许 "jane" 读取 "default" 名字空间中的 Pods
kind : RoleBinding
metadata :
name : read-pods
namespace : default
subjects :
# 你可以指定不止一个“subject(主体)”
- kind : User
name : jane # "name" 是不区分大小写的
apiGroup : rbac.authorization.k8s.io
roleRef :
# "roleRef" 指定与某 Role 或 ClusterRole 的绑定关系
kind : Role # 此字段必须是 Role 或 ClusterRole
name : pod-reader # 此字段必须与你要绑定的 Role 或 ClusterRole 的名称匹配
apiGroup : rbac.authorization.k8s.io
RoleBinding 也可以引用 ClusterRole,以将对应 ClusterRole 中定义的访问权限授予
RoleBinding 所在名字空间的资源。这种引用使得你可以跨整个集群定义一组通用的角色,
之后在多个名字空间中复用。
例如,尽管下面的 RoleBinding 引用的是一个 ClusterRole,"dave"(这里的主体,
不区分大小写)只能访问 "development" 名字空间中的 Secrets 对象,因为 RoleBinding
所在的名字空间(由其 metadata 决定)是 "development"。
apiVersion : rbac.authorization.k8s.io/v1
# 此角色绑定使得用户 "dave" 能够读取 "default" 名字空间中的 Secrets
# 你需要一个名为 "secret-reader" 的 ClusterRole
kind : RoleBinding
metadata :
name : read-secrets
# RoleBinding 的名字空间决定了访问权限的授予范围。
# 这里仅授权在 "development" 名字空间内的访问权限。
namespace : development
subjects :
- kind : User
name : dave # 'name' 是不区分大小写的
apiGroup : rbac.authorization.k8s.io
roleRef :
kind : ClusterRole
name : secret-reader
apiGroup : rbac.authorization.k8s.io
ClusterRoleBinding 示例 要跨整个集群完成访问权限的授予,你可以使用一个 ClusterRoleBinding。
下面的 ClusterRoleBinding 允许 "manager" 组内的所有用户访问任何名字空间中的
Secrets。
apiVersion : rbac.authorization.k8s.io/v1
# 此集群角色绑定允许 “manager” 组中的任何人访问任何名字空间中的 secrets
kind : ClusterRoleBinding
metadata :
name : read-secrets-global
subjects :
- kind : Group
name : manager # 'name' 是不区分大小写的
apiGroup : rbac.authorization.k8s.io
roleRef :
kind : ClusterRole
name : secret-reader
apiGroup : rbac.authorization.k8s.io
创建了绑定之后,你不能再修改绑定对象所引用的 Role 或 ClusterRole。
试图改变绑定对象的 roleRef 将导致合法性检查错误。
如果你想要改变现有绑定对象中 roleRef 字段的内容,必须删除重新创建绑定对象。
这种限制有两个主要原因:
针对不同角色的绑定是完全不一样的绑定。要求通过删除/重建绑定来更改 roleRef,
这样可以确保要赋予绑定的所有主体会被授予新的角色(而不是在允许修改
roleRef 的情况下导致所有现有主体未经验证即被授予新角色对应的权限)。 将 roleRef 设置为不可以改变,这使得可以为用户授予对现有绑定对象的 update 权限,
这样可以让他们管理主体列表,同时不能更改被授予这些主体的角色。 命令 kubectl auth reconcile 可以创建或者更新包含 RBAC 对象的清单文件,
并且在必要的情况下删除和重新创建绑定对象,以改变所引用的角色。
更多相关信息请参照命令用法和示例
对资源的引用 在 Kubernetes API 中,大多数资源都是使用对象名称的字符串表示来呈现与访问的。
例如,对于 Pod 应使用 "pods"。
RBAC 使用对应 API 端点的 URL 中呈现的名字来引用资源。
有一些 Kubernetes API 涉及 子资源(subresource) ,例如 Pod 的日志。
对 Pod 日志的请求看起来像这样:
GET /api/v1/namespaces/{namespace}/pods/{name}/log
在这里,pods 对应名字空间作用域的 Pod 资源,而 log 是 pods 的子资源。
在 RBAC 角色表达子资源时,使用斜线(/)来分隔资源和子资源。
要允许某主体读取 pods 同时访问这些 Pod 的 log 子资源,你可以这么写:
apiVersion : rbac.authorization.k8s.io/v1
kind : Role
metadata :
namespace : default
name : pod-and-pod-logs-reader
rules :
- apiGroups : ["" ]
resources : ["pods" , "pods/log" ]
verbs : ["get" , "list" ]
对于某些请求,也可以通过 resourceNames 列表按名称引用资源。
在指定时,可以将请求限定为资源的单个实例。
下面的例子中限制可以 "get" 和 "update" 一个名为 my-configmap 的
ConfigMap :
apiVersion : rbac.authorization.k8s.io/v1
kind : Role
metadata :
namespace : default
name : configmap-updater
rules :
- apiGroups : ["" ]
# 在 HTTP 层面,用来访问 ConfigMap 的资源的名称为 "configmaps"
resources : ["configmaps" ]
resourceNames : ["my-configmap" ]
verbs : ["update" , "get" ]
说明: 你不能针对 create 或者 deletecollection 请求来实施 resourceName 限制。
对于 create 操作而言,这是因为在鉴权时还不知道对象名称。
聚合的 ClusterRole 你可以将若干 ClusterRole 聚合(Aggregate) 起来,形成一个复合的 ClusterRole。
某个控制器作为集群控制面的一部分会监视带有 aggregationRule 的 ClusterRole
对象集合。aggregationRule 为控制器定义一个标签
选择算符 供后者匹配
应该组合到当前 ClusterRole 的 roles 字段中的 ClusterRole 对象。
下面是一个聚合 ClusterRole 的示例:
apiVersion : rbac.authorization.k8s.io/v1
kind : ClusterRole
metadata :
name : monitoring
aggregationRule :
clusterRoleSelectors :
- matchLabels :
rbac.example.com/aggregate-to-monitoring : "true"
rules : [] # 控制面自动填充这里的规则
如果你创建一个与某现有聚合 ClusterRole 的标签选择算符匹配的 ClusterRole,
这一变化会触发新的规则被添加到聚合 ClusterRole 的操作。
下面的例子中,通过创建一个标签同样为 rbac.example.com/aggregate-to-monitoring: true
的 ClusterRole,新的规则可被添加到 "monitoring" ClusterRole 中。
apiVersion : rbac.authorization.k8s.io/v1
kind : ClusterRole
metadata :
name : monitoring-endpoints
labels :
rbac.example.com/aggregate-to-monitoring : "true"
# 当你创建 "monitoring-endpoints" ClusterRole 时,
# 下面的规则会被添加到 "monitoring" ClusterRole 中
rules :
- apiGroups : ["" ]
resources : ["services" , "endpoints" , "pods" ]
verbs : ["get" , "list" , "watch" ]
默认的面向用户的角色 使用 ClusterRole 聚合。
这使得作为集群管理员的你可以为扩展默认规则,包括为定制资源设置规则,
比如通过 CustomResourceDefinitions 或聚合 API 服务器提供的定制资源。
例如,下面的 ClusterRoles 让默认角色 "admin" 和 "edit" 拥有管理自定义资源 "CronTabs" 的权限,
"view" 角色对 CronTab 资源拥有读操作权限。
你可以假定 CronTab 对象在 API 服务器所看到的 URL 中被命名为 "crontabs"。
apiVersion : rbac.authorization.k8s.io/v1
kind : ClusterRole
metadata :
name : aggregate-cron-tabs-edit
labels :
# 添加以下权限到默认角色 "admin" 和 "edit" 中
rbac.authorization.k8s.io/aggregate-to-admin : "true"
rbac.authorization.k8s.io/aggregate-to-edit : "true"
rules :
- apiGroups : ["stable.example.com" ]
resources : ["crontabs" ]
verbs : ["get" , "list" , "watch" , "create" , "update" , "patch" , "delete" ]
---
kind : ClusterRole
apiVersion : rbac.authorization.k8s.io/v1
metadata :
name : aggregate-cron-tabs-view
labels :
# 添加以下权限到 "view" 默认角色中
rbac.authorization.k8s.io/aggregate-to-view : "true"
rules :
- apiGroups : ["stable.example.com" ]
resources : ["crontabs" ]
verbs : ["get" , "list" , "watch" ]
Role 示例 以下示例均为从 Role 或 CLusterRole 对象中截取出来,我们仅展示其 rules 部分。
允许读取在核心 API 组 下的
"Pods":
rules :
- apiGroups : ["" ]
# 在 HTTP 层面,用来访问 Pod 的资源的名称为 "pods"
resources : ["pods" ]
verbs : ["get" , "list" , "watch" ]
允许读/写在 "extensions" 和 "apps" API 组中的 Deployment(在 HTTP 层面,对应
URL 中资源部分为 "deployments"):
rules :
- apiGroups : ["extensions" , "apps" ]
resources : ["deployments" ]
verbs : ["get" , "list" , "watch" , "create" , "update" , "patch" , "delete" ]
允许读取核心 API 组中的 "pods" 和读/写 "batch" 或 "extensions" API 组中的
"jobs":
rules :
- apiGroups : ["" ]
resources : ["pods" ]
verbs : ["get" , "list" , "watch" ]
- apiGroups : ["batch" , "extensions" ]
resources : ["jobs" ]
verbs : ["get" , "list" , "watch" , "create" , "update" , "patch" , "delete" ]
允许读取名称为 "my-config" 的 ConfigMap(需要通过 RoleBinding 绑定以
限制为某名字空间中特定的 ConfigMap):
rules :
- apiGroups : ["" ]
resources : ["configmaps" ]
resourceNames : ["my-config" ]
verbs : ["get" ]
允许读取在核心组中的 "nodes" 资源(因为 Node 是集群作用域的,所以需要
ClusterRole 绑定到 ClusterRoleBinding 才生效):
rules :
- apiGroups : ["" ]
resources : ["nodes" ]
verbs : ["get" , "list" , "watch" ]
允许针对非资源端点 /healthz 和其子路径上发起 GET 和 POST 请求
(必须在 ClusterRole 绑定 ClusterRoleBinding 才生效):
rules :
- nonResourceURLs : ["/healthz" , "/healthz/*" ] # nonResourceURL 中的 '*' 是一个全局通配符
verbs : ["get" , "post" ]
对主体的引用 RoleBinding 或者 ClusterRoleBinding 可绑定角色到某 *主体(Subject)*上。
主体可以是组,用户或者
服务账户 。
Kubernetes 用字符串来表示用户名。
用户名可以是普通的用户名,像 "alice";或者是邮件风格的名称,如 "bob@example.com",
或者是以字符串形式表达的数字 ID。
你作为 Kubernetes 管理员负责配置
身份认证模块
以便后者能够生成你所期望的格式的用户名。
注意: 前缀 system: 是 Kubernetes 系统保留的,所以你要确保
所配置的用户名或者组名不能出现上述 system: 前缀。
除了对前缀的限制之外,RBAC 鉴权系统不对用户名格式作任何要求。
在 Kubernetes 中,鉴权模块提供用户组信息。
与用户名一样,用户组名也用字符串来表示,而且对该字符串没有格式要求,
只是不能使用保留的前缀 system:。
服务账户
的用户名前缀为 system:serviceaccount:,属于前缀为 system:serviceaccounts:
的用户组。
说明: system:serviceaccount: (单数)是用于服务账户用户名的前缀;system:serviceaccounts: (复数)是用于服务账户组名的前缀。RoleBinding 示例 下面示例是 RoleBinding 中的片段,仅展示其 subjects 的部分。
对于名称为 alice@example.com 的用户:
subjects :
- kind : User
name : "alice@example.com"
apiGroup : rbac.authorization.k8s.io
对于名称为 frontend-admins 的用户组:
subjects :
- kind : Group
name : "frontend-admins"
apiGroup : rbac.authorization.k8s.io
对于 kube-system 名字空间中的默认服务账户:
subjects :
- kind : ServiceAccount
name : default
namespace : kube-system
对于任何名称空间中的 "qa" 组中所有的服务账户:
subjects :
- kind : Group
name : system:serviceaccounts:qa
apiGroup : rbac.authorization.k8s.io
对于 "development" 名称空间中 "dev" 组中的所有服务帐户:
subjects :
- kind : Group
name : system:serviceaccounts:dev
apiGroup : rbac.authorization.k8s.io
namespace : development
对于在任何名字空间中的服务账户:
subjects :
- kind : Group
name : system:serviceaccounts
apiGroup : rbac.authorization.k8s.io
对于所有已经过认证的用户:
subjects :
- kind : Group
name : system:authenticated
apiGroup : rbac.authorization.k8s.io
对于所有未通过认证的用户:
subjects :
- kind : Group
name : system:unauthenticated
apiGroup : rbac.authorization.k8s.io
对于所有用户:
subjects :
- kind : Group
name : system:authenticated
apiGroup : rbac.authorization.k8s.io
- kind : Group
name : system:unauthenticated
apiGroup : rbac.authorization.k8s.io
默认 Roles 和 Role Bindings API 服务器创建一组默认的 ClusterRole 和 ClusterRoleBinding 对象。
这其中许多是以 system: 为前缀的,用以标识对应资源是直接由集群控制面管理的。
所有的默认 ClusterRole 和 ClusterRoleBinding 都有
kubernetes.io/bootstrapping=rbac-defaults
标签。
注意: 在修改名称包含 system: 前缀的 ClusterRole 和 ClusterRoleBinding
时要格外小心。
对这些资源的更改可能导致集群无法继续工作。
自动协商 在每次启动时,API 服务器都会更新默认 ClusterRole 以添加缺失的各种权限,并更新
默认的 ClusterRoleBinding 以增加缺失的的各类主体。
这种自动协商机制允许集群去修复一些不小心发生的修改,并且有助于保证角色和角色绑定
在新的发行版本中有权限或主体变更时仍然保持最新。
如果要禁止此功能,请将默认 ClusterRole 以及 ClusterRoleBinding 的
rbac.authorization.kubernetes.io/autoupdate 注解设置成 false。
注意,缺少默认权限和角色绑定主体可能会导致集群无法正常工作。
如果基于 RBAC 的鉴权机制被启用,则自动协商功能默认是被启用的。
API 发现角色 无论是经过身份验证的还是未经过身份验证的用户,默认的角色绑定都授权他们读取被认为
是可安全地公开访问的 API( 包括 CustomResourceDefinitions)。
如果要禁用匿名的未经过身份验证的用户访问,请在 API 服务器配置中中添加
--anonymous-auth=false 的配置选项。
通过运行命令 kubectl 可以查看这些角色的配置信息:
kubectl get clusterroles system:discovery -o yaml
说明: 如果你编辑该 ClusterRole,你所作的变更会被 API 服务器在重启时自动覆盖,这是通过
自动协商 机制完成的。要避免这类覆盖操作,
要么不要手动编辑这些角色,要么禁止自动协商机制。
Kubernetes RBAC API 发现角色 默认 ClusterRole 默认 ClusterRoleBinding 描述 system:basic-user system:authenticated 组允许用户以只读的方式去访问他们自己的基本信息。在 1.14 版本之前,这个角色在默认情况下也绑定在 system:unauthenticated 上。 system:discovery system:authenticated 组允许以只读方式访问 API 发现端点,这些端点用来发现和协商 API 级别。
在 1.14 版本之前,这个角色在默认情况下绑定在 system:unauthenticated 上。 system:public-info-viewer system:authenticated 和 system:unauthenticated 组允许对集群的非敏感信息进行只读访问,它是在 1.14 版本中引入的。
面向用户的角色 一些默认的 ClusterRole 不是以前缀 system: 开头的。这些是面向用户的角色。
它们包括超级用户(Super-User)角色(cluster-admin)、
使用 ClusterRoleBinding 在集群范围内完成授权的角色(cluster-status)、
以及使用 RoleBinding 在特定名字空间中授予的角色(admin、edit、view)。
面向用户的 ClusterRole 使用 ClusterRole 聚合 以允许管理员在
这些 ClusterRole 上添加用于定制资源的规则。如果想要添加规则到 admin、edit 或者 view,
可以创建带有以下一个或多个标签的 ClusterRole:
metadata :
labels :
rbac.authorization.k8s.io/aggregate-to-admin : "true"
rbac.authorization.k8s.io/aggregate-to-edit : "true"
rbac.authorization.k8s.io/aggregate-to-view : "true"
默认 ClusterRole 默认 ClusterRoleBinding 描述 cluster-admin system:masters 组允许超级用户在平台上的任何资源上执行所有操作。
当在 ClusterRoleBinding 中使用时,可以授权对集群中以及所有名字空间中的全部资源进行完全控制。
当在 RoleBinding 中使用时,可以授权控制 RoleBinding 所在名字空间中的所有资源,包括名字空间本身。 admin 无 允许管理员访问权限,旨在使用 RoleBinding 在名字空间内执行授权。
如果在 RoleBinding 中使用,则可授予对名字空间中的大多数资源的读/写权限,
包括创建角色和角色绑定的能力。
但是它不允许对资源配额或者名字空间本身进行写操作。 edit 无 允许对名字空间的大多数对象进行读/写操作。
它不允许查看或者修改角色或者角色绑定。
不过,此角色可以访问 Secret,以名字空间中任何 ServiceAccount 的身份运行 Pods,
所以可以用来了解名字空间内所有服务账户的 API 访问级别。 view 无 允许对名字空间的大多数对象有只读权限。
它不允许查看角色或角色绑定。此角色不允许查看 Secrets,因为读取 Secret 的内容意味着可以访问名字空间中
ServiceAccount 的凭据信息,进而允许利用名字空间中任何 ServiceAccount 的
身份访问 API(这是一种特权提升)。
核心组件角色 默认 ClusterRole 默认 ClusterRoleBinding 描述 system:kube-scheduler system:kube-scheduler 用户允许访问 scheduler
组件所需要的资源。 system:volume-scheduler system:kube-scheduler 用户允许访问 kube-scheduler 组件所需要的卷资源。 system:kube-controller-manager system:kube-controller-manager 用户允许访问控制器管理器
组件所需要的资源。
各个控制回路所需要的权限在控制器角色 详述。 system:node 无 允许访问 kubelet 所需要的资源,包括对所有 Secret 的读操作和对所有 Pod 状态对象的写操作。 你应该使用 Node 鉴权组件 和
NodeRestriction 准入插件
而不是 system:node 角色。同时基于 kubelet 上调度执行的 Pod 来授权
kubelet 对 API 的访问。
system:node 角色的意义仅是为了与从 v1.8 之前版本升级而来的集群兼容。
system:node-proxier system:kube-proxy 用户允许访问 kube-proxy
组件所需要的资源。
其他组件角色 默认 ClusterRole 默认 ClusterRoleBinding 描述 system:auth-delegator 无 允许将身份认证和鉴权检查操作外包出去。
这种角色通常用在插件式 API 服务器上,以实现统一的身份认证和鉴权。 system:heapster 无 为 Heapster 组件(已弃用)定义的角色。 system:kube-aggregator 无 为 kube-aggregator 组件定义的角色。 system:kube-dns 在 kube-system 名字空间中的 kube-dns 服务账户 为 kube-dns 组件定义的角色。 system:kubelet-api-admin 无 允许 kubelet API 的完全访问权限。 system:node-bootstrapper 无 允许访问执行
kubelet TLS 启动引导
所需要的资源。 system:node-problem-detector 无 为 node-problem-detector 组件定义的角色。 system:persistent-volume-provisioner 无 允许访问大部分
动态卷驱动
所需要的资源。 system:monitoring system:monitoring 组允许对控制平面监控端点的读取访问(例如:kube-apiserver
存活和就绪端点(/healthz 、/livez 、/readyz ),
各个健康检查端点(/healthz/* 、/livez/* 、/readyz/* )和 /metrics )。
请注意,各个运行状况检查端点和度量标准端点可能会公开敏感信息。
内置控制器的角色 Kubernetes 控制器管理器
运行内建于 Kubernetes 控制面的控制器 。
当使用 --use-service-account-credentials 参数启动时, kube-controller-manager
使用单独的服务账户来启动每个控制器。
每个内置控制器都有相应的、前缀为 system:controller: 的角色。
如果控制管理器启动时未设置 --use-service-account-credentials,
它使用自己的身份凭据来运行所有的控制器,该身份必须被授予所有相关的角色。
这些角色包括:
system:controller:attachdetach-controllersystem:controller:certificate-controllersystem:controller:clusterrole-aggregation-controllersystem:controller:cronjob-controllersystem:controller:daemon-set-controllersystem:controller:deployment-controllersystem:controller:disruption-controllersystem:controller:endpoint-controllersystem:controller:expand-controllersystem:controller:generic-garbage-collectorsystem:controller:horizontal-pod-autoscalersystem:controller:job-controllersystem:controller:namespace-controllersystem:controller:node-controllersystem:controller:persistent-volume-bindersystem:controller:pod-garbage-collectorsystem:controller:pv-protection-controllersystem:controller:pvc-protection-controllersystem:controller:replicaset-controllersystem:controller:replication-controllersystem:controller:resourcequota-controllersystem:controller:root-ca-cert-publishersystem:controller:route-controllersystem:controller:service-account-controllersystem:controller:service-controllersystem:controller:statefulset-controllersystem:controller:ttl-controller初始化与预防权限提升 RBAC API 会阻止用户通过编辑角色或者角色绑定来提升权限。
由于这一点是在 API 级别实现的,所以在 RBAC 鉴权组件未启用的状态下依然可以正常工作。
对角色创建或更新的限制 只有在符合下列条件之一的情况下,你才能创建/更新角色:
你已经拥有角色中包含的所有权限,且其作用域与正被修改的对象作用域相同。
(对 ClusterRole 而言意味着集群范围,对 Role 而言意味着相同名字空间或者集群范围)。 你被显式授权在 rbac.authorization.k8s.io API 组中的 roles 或 clusterroles 资源
使用 escalate 动词。 例如,如果 user-1 没有列举集群范围所有 Secret 的权限,他将不能创建包含该权限的 ClusterRole。
若要允许用户创建/更新角色:
根据需要赋予他们一个角色,允许他们根据需要创建/更新 Role 或者 ClusterRole 对象。 授予他们在所创建/更新角色中包含特殊权限的权限:隐式地为他们授权(如果它们试图创建或者更改 Role 或 ClusterRole 的权限,
但自身没有被授予相应权限,API 请求将被禁止)。 通过允许他们在 Role 或 ClusterRole 资源上执行 escalate 动作显式完成授权。
这里的 roles 和 clusterroles 资源包含在 rbac.authorization.k8s.io API 组中。 对角色绑定创建或更新的限制 只有你已经具有了所引用的角色中包含的全部权限时,或者你被授权在所引用的角色上执行 bind
动词时,你才可以创建或更新角色绑定。这里的权限与角色绑定的作用域相同。
例如,如果用户 user-1 没有列举集群范围所有 Secret 的能力,则他不可以创建
ClusterRoleBinding 引用授予该许可权限的角色。
如要允许用户创建或更新角色绑定:
赋予他们一个角色,使得他们能够根据需要创建或更新 RoleBinding 或 ClusterRoleBinding
对象。 授予他们绑定某特定角色所需要的许可权限:隐式授权下,可以将角色中包含的许可权限授予他们; 显式授权下,可以授权他们在特定 Role (或 ClusterRole)上执行 bind 动词的权限。 例如,下面的 ClusterRole 和 RoleBinding 将允许用户 user-1 把名字空间 user-1-namespace
中的 admin、edit 和 view 角色赋予其他用户:
apiVersion : rbac.authorization.k8s.io/v1
kind : ClusterRole
metadata :
name : role-grantor
rules :
- apiGroups : ["rbac.authorization.k8s.io" ]
resources : ["rolebindings" ]
verbs : ["create" ]
- apiGroups : ["rbac.authorization.k8s.io" ]
resources : ["clusterroles" ]
verbs : ["bind" ]
# 忽略 resourceNames 意味着允许绑定任何 ClusterRole
resourceNames : ["admin" ,"edit" ,"view" ]
---
apiVersion : rbac.authorization.k8s.io/v1
kind : RoleBinding
metadata :
name : role-grantor-binding
namespace : user-1-namespace
roleRef :
apiGroup : rbac.authorization.k8s.io
kind : ClusterRole
name : role-grantor
subjects :
- apiGroup : rbac.authorization.k8s.io
kind : User
name : user-1
当启动引导第一个角色和角色绑定时,需要为初始用户授予他们尚未拥有的权限。
对初始角色和角色绑定进行初始化时需要:
使用用户组为 system:masters 的凭据,该用户组由默认绑定关联到 cluster-admin
这个超级用户角色。 如果你的 API 服务器启动时启用了不安全端口(使用 --insecure-port), 你也可以通过
该端口调用 API ,这样的操作会绕过身份验证或鉴权。 一些命令行工具 kubectl create role创建 Role 对象,定义在某一名字空间中的权限。例如:
kubectl create clusterrole创建 ClusterRole 对象。例如:
kubectl create rolebinding在特定的名字空间中对 Role 或 ClusterRole 授权。例如:
kubectl create clusterrolebinding在整个集群(所有名字空间)中用 ClusterRole 授权。例如:
kubectl auth reconcile使用清单文件来创建或者更新 rbac.authorization.k8s.io/v1 API 对象。
尚不存在的对象会被创建,如果对应的名字空间也不存在,必要的话也会被创建。
已经存在的角色会被更新,使之包含输入对象中所给的权限。如果指定了
--remove-extra-permissions,可以删除额外的权限。
已经存在的绑定也会被更新,使之包含输入对象中所给的主体。如果指定了
--remove-extra-permissions,则可以删除多余的主体。
例如:
查看 CLI 帮助获取详细的用法。
服务账户权限 默认的 RBAC 策略为控制面组件、节点和控制器授予权限。
但是不会对 kube-system 名字空间之外的服务账户授予权限。
(除了授予所有已认证用户的发现权限)
这使得你可以根据需要向特定服务账户授予特定权限。
细粒度的角色绑定可带来更好的安全性,但需要更多精力管理。
粗粒度的授权可能导致服务账户被授予不必要的 API 访问权限(甚至导致潜在的权限提升),
但更易于管理。
按从最安全到最不安全的顺序,存在以下方法:
为特定应用的服务账户授予角色(最佳实践)
这要求应用在其 Pod 规约中指定 serviceAccountName,
并额外创建服务账户(包括通过 API、应用程序清单、kubectl create serviceaccount 等)。
例如,在名字空间 "my-namespace" 中授予服务账户 "my-sa" 只读权限:
kubectl create rolebinding my-sa-view \
--clusterrole= view \
--serviceaccount= my-namespace:my-sa \
--namespace= my-namespace
将角色授予某名字空间中的 "default" 服务账户
如果某应用没有指定 serviceAccountName,那么它将使用 "default" 服务账户。
说明: "default" 服务账户所具有的权限会被授予给名字空间中所有未指定
serviceAccountName 的 Pod。
例如,在名字空间 "my-namespace" 中授予服务账户 "default" 只读权限:
kubectl create rolebinding default-view \
--clusterrole= view \
--serviceaccount= my-namespace:default \
--namespace= my-namespace
许多插件组件 在 kube-system
名字空间以 "default" 服务账户运行。
要允许这些插件组件以超级用户权限运行,需要将集群的 cluster-admin 权限授予
kube-system 名字空间中的 "default" 服务账户。
说明: 启用这一配置意味着在 kube-system 名字空间中包含以超级用户账号来访问 API
的 Secrets。
kubectl create clusterrolebinding add-on-cluster-admin \
--clusterrole= cluster-admin \
--serviceaccount= kube-system:default
将角色授予名字空间中所有服务账户
如果你想要名字空间中所有应用都具有某角色,无论它们使用的什么服务账户,
可以将角色授予该名字空间的服务账户组。
例如,在名字空间 "my-namespace" 中的只读权限授予该名字空间中的所有服务账户:
kubectl create rolebinding serviceaccounts-view \
--clusterrole= view \
--group= system:serviceaccounts:my-namespace \
--namespace= my-namespace
在集群范围内为所有服务账户授予一个受限角色(不鼓励)
如果你不想管理每一个名字空间的权限,你可以向所有的服务账户授予集群范围的角色。
例如,为集群范围的所有服务账户授予跨所有名字空间的只读权限:
kubectl create clusterrolebinding serviceaccounts-view \
--clusterrole= view \
--group= system:serviceaccounts
授予超级用户访问权限给集群范围内的所有服务帐户(强烈不鼓励)
如果你不关心如何区分权限,你可以将超级用户访问权限授予所有服务账户。
警告: 这样做会允许所有应用都对你的集群拥有完全的访问权限,并将允许所有能够读取
Secret(或创建 Pod)的用户对你的集群有完全的访问权限。
kubectl create clusterrolebinding serviceaccounts-cluster-admin \
--clusterrole= cluster-admin \
--group= system:serviceaccounts
从 ABAC 升级 原来运行较老版本 Kubernetes 的集群通常会使用限制宽松的 ABAC 策略,
包括授予所有服务帐户全权访问 API 的能力。
默认的 RBAC 策略为控制面组件、节点和控制器等授予有限的权限,但不会为
kube-system 名字空间外的服务账户授权
(除了授予所有认证用户的发现权限之外)。
这样做虽然安全得多,但可能会干扰期望自动获得 API 权限的现有工作负载。
这里有两种方法来完成这种转换:
并行鉴权 同时运行 RBAC 和 ABAC 鉴权模式, 并指定包含
现有的 ABAC 策略
的策略文件:
--authorization-mode= RBAC,ABAC --authorization-policy-file= mypolicy.json
关于命令行中的第一个选项:如果早期的鉴权组件,例如 Node,拒绝了某个请求,则
RBAC 鉴权组件尝试对该 API 请求鉴权。如果 RBAC 也拒绝了该 API 请求,则运行 ABAC
鉴权组件。这意味着被 RBAC 或 ABAC 策略所允许的任何请求都是被允许的请求。
如果 API 服务器启动时,RBAC 组件的日志级别为 5 或更高(--vmodule=rbac*=5 或 --v=5),
你可以在 API 服务器的日志中看到 RBAC 的细节 (前缀 RBAC:)
你可以使用这些信息来确定需要将哪些角色授予哪些用户、组或服务帐户。
一旦你将角色授予服务账户 ,工作负载运行时
在服务器日志中没有出现 RBAC 拒绝消息,就可以删除 ABAC 鉴权器。
宽松的 RBAC 权限 你可以使用 RBAC 角色绑定在多个场合使用宽松的策略。
警告: 下面的策略允许 所有 服务帐户充当集群管理员。
容器中运行的所有应用程序都会自动收到服务帐户的凭据,可以对 API 执行任何操作,
包括查看 Secrets 和修改权限。这一策略是不被推荐的。
kubectl create clusterrolebinding permissive-binding \
--clusterrole= cluster-admin \
--user= admin \
--user= kubelet \
--group= system:serviceaccounts
在你完成到 RBAC 的迁移后,应该调整集群的访问控制,确保相关的策略满足你的
信息安全需求。
6.5.9 - 使用 Node 鉴权 节点鉴权是一种特殊用途的鉴权模式,专门对 kubelet 发出的 API 请求进行鉴权。
概述 节点鉴权器允许 kubelet 执行 API 操作。包括:
读取操作:
services endpoints nodes pods secrets、configmaps、pvcs 以及绑定到 kubelet 节点的与 pod 相关的持久卷 写入操作:
节点和节点状态(启用 NodeRestriction 准入插件以限制 kubelet 只能修改自己的节点) Pod 和 Pod 状态 (启用 NodeRestriction 准入插件以限制 kubelet 只能修改绑定到自身的 Pod) 事件 鉴权相关操作:
对于基于 TLS 的启动引导过程时使用的 certificationsigningrequests API 的读/写权限 为委派的身份验证/授权检查创建 tokenreviews 和 subjectaccessreviews 的能力 在将来的版本中,节点鉴权器可能会添加或删除权限,以确保 kubelet 具有正确操作所需的最小权限集。
为了获得节点鉴权器的授权,kubelet 必须使用一个凭证以表示它在 system:nodes 组中,用户名为 system:node:<nodeName>。
上述的组名和用户名格式要与 kubelet TLS 启动引导 过程中为每个 kubelet 创建的标识相匹配。
要启用节点授权器,请使用 --authorization-mode = Node 启动 apiserver。
要限制 kubelet 具有写入权限的 API 对象,请使用 --enable-admission-plugins=...,NodeRestriction,... 启动 apiserver,从而启用 NodeRestriction 准入插件。
迁移考虑因素 在 system:nodes 组之外的 Kubelet system:nodes 组之外的 kubelet 不会被 Node 鉴权模式授权,并且需要继续通过当前授权它们的机制来授权。
节点准入插件不会限制来自这些 kubelet 的请求。
具有无差别用户名的 Kubelet 在一些部署中,kubelet 具有 system:nodes 组的凭证,但是无法给出它们所关联的节点的标识,因为它们没有 system:node:... 格式的用户名。
这些 kubelet 不会被 Node 授权模式授权,并且需要继续通过当前授权它们的任何机制来授权。
因为默认的节点标识符实现不会把它当作节点身份标识,NodeRestriction 准入插件会忽略来自这些 kubelet 的请求。
相对于以前使用 RBAC 的版本的更新 升级的 1.7 之前的使用 RBAC 的集群将继续按原样运行,因为 system:nodes 组绑定已经存在。
如果集群管理员希望开始使用 Node 鉴权器和 NodeRestriction 准入插件来限制节点对 API 的访问,这一需求可以通过下列操作来完成且不会影响已部署的应用:
启用 Node 鉴权模式 (--authorization-mode=Node,RBAC) 和 NodeRestriction 准入插件 确保所有 kubelet 的凭据符合组/用户名要求 审核 apiserver 日志以确保 Node 鉴权器不会拒绝来自 kubelet 的请求(日志中没有持续的 NODE DENY 消息) 删除 system:node 集群角色绑定 RBAC 节点权限 在 1.6 版本中,当使用 RBAC 鉴权模式 时,system:nodes 集群角色会被自动绑定到 system:node 组。
在 1.7 版本中,不再推荐将 system:nodes 组自动绑定到 system:node 角色,因为节点鉴权器通过对 secret 和 configmap 访问的额外限制完成了相同的任务。
如果同时启用了 Node 和 RBAC 授权模式,1.7 版本则不会创建 system:nodes 组到 system:node 角色的自动绑定。
在 1.8 版本中,绑定将根本不会被创建。
使用 RBAC 时,将继续创建 system:node 集群角色,以便与将其他用户或组绑定到该角色的部署方法兼容。
6.5.10 - Webhook 模式 WebHook 是一种 HTTP 回调:某些条件下触发的 HTTP POST 请求;通过 HTTP POST 发送的简单事件通知。一个基于 web 应用实现的 WebHook 会在特定事件发生时把消息发送给特定的 URL。
具体来说,当在判断用户权限时,Webhook 模式会使 Kubernetes 查询外部的 REST 服务。
配置文件格式 Webhook 模式需要一个 HTTP 配置文件,通过 --authorization-webhook-config-file=SOME_FILENAME 的参数声明。
配置文件的格式使用 kubeconfig 。在文件中,"users" 代表着 API 服务器的 webhook,而 "cluster" 代表着远程服务。
使用 HTTPS 客户端认证的配置例子:
# Kubernetes API 版本
apiVersion : v1
# API 对象种类
kind : Config
# clusters 代表远程服务。
clusters :
- name : name-of-remote-authz-service
cluster :
# 对远程服务进行身份认证的 CA。
certificate-authority : /path/to/ca.pem
# 远程服务的查询 URL。必须使用 'https'。
server : https://authz.example.com/authorize
# users 代表 API 服务器的 webhook 配置
users :
- name : name-of-api-server
user :
client-certificate : /path/to/cert.pem # webhook plugin 使用 cert
client-key : /path/to/key.pem # cert 所对应的 key
# kubeconfig 文件必须有 context。需要提供一个给 API 服务器。
current-context : webhook
contexts :
- context :
cluster : name-of-remote-authz-service
user : name-of-api-server
name : webhook
请求载荷 在做认证决策时,API 服务器会 POST 一个 JSON 序列化的 authorization.k8s.io/v1beta1 SubjectAccessReview 对象来描述这个动作。这个对象包含了描述用户请求的字段,同时也包含了需要被访问资源或请求特征的具体信息。
需要注意的是 webhook API 对象与其他 Kubernetes API 对象一样都同样都服从版本兼容规则 。实施人员应该了解 beta 对象的更宽松的兼容性承诺,同时确认请求的 "apiVersion" 字段能被正确地反序列化。此外,API 服务器还必须启用 authorization.k8s.io/v1beta1 API 扩展组 (--runtime-config=authorization.k8s.io/v1beta1=true)。
一个请求内容的例子:
{
"apiVersion" : "authorization.k8s.io/v1beta1" ,
"kind" : "SubjectAccessReview" ,
"spec" : {
"resourceAttributes" : {
"namespace" : "kittensandponies" ,
"verb" : "get" ,
"group" : "unicorn.example.org" ,
"resource" : "pods"
},
"user" : "jane" ,
"group" : [
"group1" ,
"group2"
]
}
}
期待远程服务填充请求的 status 字段并响应允许或禁止访问。响应主体的 spec 字段被忽略,可以省略。允许的响应将返回:
{
"apiVersion" : "authorization.k8s.io/v1beta1" ,
"kind" : "SubjectAccessReview" ,
"status" : {
"allowed" : true
}
}
为了禁止访问,有两种方法。
在大多数情况下,第一种方法是首选方法,它指示授权 webhook 不允许或对请求"无意见",但是,如果配置了其他授权者,则可以给他们机会允许请求。如果没有其他授权者,或者没有一个授权者,则该请求被禁止。webhook 将返回:
{
"apiVersion" : "authorization.k8s.io/v1beta1" ,
"kind" : "SubjectAccessReview" ,
"status" : {
"allowed" : false ,
"reason" : "user does not have read access to the namespace"
}
}
第二种方法立即拒绝其他配置的授权者进行短路评估。仅应由对集群的完整授权者配置有详细了解的 webhook 使用。webhook 将返回:
{
"apiVersion" : "authorization.k8s.io/v1beta1" ,
"kind" : "SubjectAccessReview" ,
"status" : {
"allowed" : false ,
"denied" : true ,
"reason" : "user does not have read access to the namespace"
}
}
对于非资源的路径访问是这么发送的:
{
"apiVersion" : "authorization.k8s.io/v1beta1" ,
"kind" : "SubjectAccessReview" ,
"spec" : {
"nonResourceAttributes" : {
"path" : "/debug" ,
"verb" : "get"
},
"user" : "jane" ,
"group" : [
"group1" ,
"group2"
]
}
}
非资源类的路径包括:/api, /apis, /metrics, /resetMetrics,
/logs, /debug, /healthz, /swagger-ui/, /swaggerapi/, /ui, 和
/version。客户端需要访问 /api, /api/*, /apis, /apis/*, 和 /version 以便
能发现服务器上有什么资源和版本。对于其他非资源类的路径访问在没有 REST API 访问限制的情况下拒绝。
更多信息可以参考 authorization.v1beta1 API 对象和webhook.go 。
6.5.11 - 使用 ABAC 鉴权 基于属性的访问控制(Attribute-based access control - ABAC)定义了访问控制范例,其中通过使用将属性组合在一起的策略来向用户授予访问权限。
策略文件格式 基于 ABAC 模式,可以这样指定策略文件 --authorization-policy-file=SOME_FILENAME。
此文件格式是 JSON Lines ,不应存在封闭的列表或映射,每行一个映射。
每一行都是一个策略对象,策略对象是具有以下属性的映射:
版本控制属性:apiVersion,字符串类型:有效值为abac.authorization.kubernetes.io/v1beta1,允许对策略格式进行版本控制和转换。kind,字符串类型:有效值为 Policy,允许对策略格式进行版本控制和转换。 spec 配置为具有以下映射的属性:主体匹配属性:user,字符串类型;来自 --token-auth-file 的用户字符串,如果你指定 user,它必须与验证用户的用户名匹配。group,字符串类型;如果指定 group,它必须与经过身份验证的用户的一个组匹配,system:authenticated匹配所有经过身份验证的请求。system:unauthenticated匹配所有未经过身份验证的请求。 资源匹配属性:apiGroup,字符串类型;一个 API 组。例: extensions 通配符:*匹配所有 API 组。 namespace,字符串类型;一个命名空间。例如:kube-system 通配符:*匹配所有资源请求。 resource,字符串类型;资源类型。 非资源匹配属性:nonResourcePath,字符串类型;非资源请求路径。例如:/version或 /apis 通配符:* 匹配所有非资源请求。/foo/* 匹配 /foo/ 的所有子路径。 readonly,键入布尔值,如果为 true,则表示该策略仅适用于 get、list 和 watch 操作。说明: 属性未设置等效于属性被设置为对应类型的零值( 例如空字符串、0、false),然而,出于可读性考虑,应尽量选择不设置这类属性。
在将来,策略可能以 JSON 格式表示,并通过 REST 界面进行管理。
鉴权算法 请求具有与策略对象的属性对应的属性。
当接收到请求时,确定属性。未知属性设置为其类型的零值(例如:空字符串,0,false)。
设置为 "*" 的属性将匹配相应属性的任何值。
检查属性的元组,以匹配策略文件中的每个策略。如果至少有一行匹配请求属性,则请求被鉴权(但仍可能无法通过稍后的合法性检查)。
要允许任何经过身份验证的用户执行某些操作,请将策略组属性设置为 "system:authenticated"。
要允许任何未经身份验证的用户执行某些操作,请将策略组属性设置为 "system:authentication"。
要允许用户执行任何操作,请使用 apiGroup,命名空间,
资源和 nonResourcePath 属性设置为 "*" 的策略。
要允许用户执行任何操作,请使用设置为 "*" 的 apiGroup,namespace,resource 和 nonResourcePath 属性编写策略。
Kubectl Kubectl 使用 api-server 的 /api 和 /apis 端点来发现服务资源类型,并使用位于 /openapi/v2 的模式信息来验证通过创建/更新操作发送到 API 的对象。
当使用 ABAC 鉴权时,这些特殊资源必须显式地通过策略中的 nonResourcePath 属性暴露出来(参见下面的 示例 ):
/api,/api/*,/apis和 /apis/* 用于 API 版本协商。/version 通过 kubectl version 检索服务器版本。/swaggerapi/* 用于创建 / 更新操作。要检查涉及到特定 kubectl 操作的 HTTP 调用,您可以调整详细程度:
kubectl --v=8 version
例子 Alice 可以对所有资源做任何事情:
{"apiVersion" : "abac.authorization.kubernetes.io/v1beta1" , "kind" : "Policy" , "spec" : {"user" : "alice" , "namespace" : "*" , "resource" : "*" , "apiGroup" : "*" }}
Kubelet 可以读取任何 pod:
{"apiVersion" : "abac.authorization.kubernetes.io/v1beta1" , "kind" : "Policy" , "spec" : {"user" : "kubelet" , "namespace" : "*" , "resource" : "pods" , "readonly" : true }}
Kubelet 可以读写事件:
{"apiVersion" : "abac.authorization.kubernetes.io/v1beta1" , "kind" : "Policy" , "spec" : {"user" : "kubelet" , "namespace" : "*" , "resource" : "events" }}
Bob 可以在命名空间 projectCaribou 中读取 pod:
{"apiVersion" : "abac.authorization.kubernetes.io/v1beta1" , "kind" : "Policy" , "spec" : {"user" : "bob" , "namespace" : "projectCaribou" , "resource" : "pods" , "readonly" : true }}
任何人都可以对所有非资源路径进行只读请求:
{"apiVersion" : "abac.authorization.kubernetes.io/v1beta1" , "kind" : "Policy" , "spec" : {"group" : "system:authenticated" , "readonly" : true , "nonResourcePath" : "*" }}
{"apiVersion" : "abac.authorization.kubernetes.io/v1beta1" , "kind" : "Policy" , "spec" : {"group" : "system:unauthenticated" , "readonly" : true , "nonResourcePath" : "*" }}
完整文件示例
服务帐户的快速说明 服务帐户自动生成用户。用户名是根据命名约定生成的:
system:serviceaccount:<namespace>:<serviceaccountname>
创建新的命名空间也会导致创建一个新的服务帐户:
system:serviceaccount:<namespace>:default
例如,如果要将 API 的 kube-system 完整权限中的默认服务帐户授予,则可以将此行添加到策略文件中:
{"apiVersion" :"abac.authorization.kubernetes.io/v1beta1" ,"kind" :"Policy" ,"spec" :{"user" :"system:serviceaccount:kube-system:default" ,"namespace" :"*" ,"resource" :"*" ,"apiGroup" :"*" }}
需要重新启动 apiserver 以获取新的策略行。
6.6 - API 参考
6.7 - 安装工具 6.7.1 - Kubeadm Kubeadm 是一个提供了 kubeadm init 和 kubeadm join 的工具,作为创建 Kubernetes 集群的 “快捷途径” 的最佳实践。
kubeadm 通过执行必要的操作来启动和运行最小可用集群。按照设计,它只关注启动引导,而非配置机器。同样的,安装各种 “锦上添花” 的扩展,例如 Kubernetes Dashboard,
监控方案,以及特定云平台的扩展,都不在讨论范围内。
相反,我们希望在 kubeadm 之上构建更高级别以及更加合规的工具,理想情况下,使用 kubeadm 作为所有部署工作的基准将会更加易于创建一致性集群。
如何安装 要安装 kubeadm, 请查阅安装指南 .
接下来
6.7.1.1 - 创建 Kubeadm 6.7.1.1.1 - 摘要 ┌──────────────────────────────────────────────────────────┐
│ KUBEADM │
│ 轻松创建一个安全的 Kubernetes 集群 │
│ │
│ 给我们反馈意见的地址: │
│ https://github.com/kubernetes/kubeadm/issues │
└──────────────────────────────────────────────────────────┘
用途示例:
创建一个有两台机器的集群,包含一个主节点(用来控制集群),和一个工作节点(运行您的工作负载,像 Pod 和 Deployment)。
┌──────────────────────────────────────────────────────────┐
│ 在第一台机器上: │
├──────────────────────────────────────────────────────────┤
│ control-plane# kubeadm init │
└──────────────────────────────────────────────────────────┘
┌──────────────────────────────────────────────────────────┐
│ 在第二台机器上: │
├──────────────────────────────────────────────────────────┤
│ worker# kubeadm join <arguments-returned-from-init>│
└──────────────────────────────────────────────────────────┘
您可以重复第二步,向集群添加更多机器。
选项 -h, --help kubeadm 操作的帮助信息 --rootfs string [实验] 指向 '真实' 宿主机根文件系统的路径。
6.7.1.1.2 - 概要 kubeadm 实验子命令
选项 从父命令继承的选项 --rootfs string [实验] 指向 '真实' 宿主机的根文件系统的路径。
6.7.1.1.3 - 概要 kubeconfig 文件应用程序。
Alpha 免责声明:此命令当前为 alpha 功能。
选项 -h, --help kubeconfig 操作的帮助命令
从父命令继承的选项 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
6.7.1.1.4 - 概要 为其他用户输出 kubeconfig 文件。
Alpha 免责声明:此命令当前为 Alpha 功能。
kubeadm alpha kubeconfig user [flags]
示例 # 使用名为 bar 的 kubeadm 配置文件为名为 foo 的另一用户输出 kubeconfig 文件
kubeadm alpha kubeconfig user --client-name=foo --config=bar
选项 --client-name string 用户名。如果生成客户端证书,则用作其 CN。 --config string 指向 kubeadm 配置文件的路径 -h, --help user 操作的帮助命令 --org stringSlice 客户端证书的组织。如果创建客户端证书,此值将用作其 O 字段值。 --token string 应该用此 kubeconfig 的身份验证机制的令牌,而不是客户端证书
从父命令继承的选项 --rootfs string [实验] 指向 '真实' 宿主机的根目录。
6.7.1.1.5 - 概要 此命令并非设计用来单独运行。请参阅可用子命令列表。
选项 -h, --help kubelet 操作的帮助命令
从父命令继承的选项 --rootfs string [实验] 指向 '真实' 宿主机的根目录。
6.7.1.1.6 - 概要 此命令并非设计用来单独运行。请参阅可用子命令列表。
选项 从父命令继承的选项 --rootfs string [实验] 指向宿主机上的 '实际' 根文件系统的路径。
6.7.1.1.7 - 概要 针对集群中的 kubelet-config-1.X ConfigMap 启用或更新节点的动态 kubelet 配置,其中 X 是所需 kubelet 版本的次要版本。
警告:此功能仍处于试验阶段,默认情况下处于禁用状态。仅当知道自己在做什么时才启用它,因为在此阶段它可能会产生令人惊讶的副作用。
Alpha 免责声明:此命令当前为 Alpha 功能。
kubeadm alpha kubelet config enable-dynamic [flags]
示例 # 为节点启用动态 kubelet 配置。
kubeadm alpha phase kubelet enable-dynamic-config --node-name node-1 --kubelet-version 1.16.0
WARNING: This feature is still experimental, and disabled by default. Enable only if you know what you are doing, as it
may have surprising side-effects at this stage.
选项 -h, --help enable-dynamic 操作的帮助命令 --kubeconfig string 默认值: "/etc/kubernetes/admin.conf" 与集群通信时使用的 kubeconfig 文件。如果未设置该标志,则可以在一组标准位置中搜索现有的 kubeconfig 文件。 --kubelet-version string kubelet 所需版本 --node-name string 应该启用动态 kubelet 配置节点的名称
从父命令继承的选项 --rootfs string [实验] 指向 '真实' 宿主机的根目录。
6.7.1.1.8 - 概要 此命令并非设计用来单独运行。请参阅可用子命令列表。
选项 -h, --help selfhosting 操作的帮助命令
从父命令继承的选项 --rootfs string [实验] 指向 '真实' 宿主机的根目录。
6.7.1.1.9 - 概要 将用于控制平面组件的静态 Pod 文件转换为通过 Kubernetes API 配置的自托管 DaemonSet。
有关自托管的限制,请参阅相关文档。
Alpha 免责声明:此命令当前为 alpha 功能。
kubeadm alpha selfhosting pivot [flags]
示例 # 将静态 Pod 托管的控制平面转换为自托管的控制平面。
kubeadm alpha phase self-hosting convert-from-staticpods
选项 --cert-dir string 默认值:"/etc/kubernetes/pki" 证书存储的路径 --config string kubeadm 配置文件的路径。 -f, --force 在不提示确认的情况下转换集群 -h, --help pivot 操作的帮助命令 --kubeconfig string 默认值:"/etc/kubernetes/admin.conf" 与集群通信时使用的 kubeconfig 文件。如果未设置该参数,则可以在一组标准位置中搜索现有的 kubeconfig 文件。 -s, --store-certs-in-secrets 启用 secret 存储证书
从父命令继承的选项 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
6.7.1.1.10 - 概要 与处理 kubernetes 证书相关的命令
选项 继承于父命令的选项 --rootfs string [实验] 到'真实'主机根文件系统的路径。
6.7.1.1.11 - 概要 该命令将打印出可以与 "init" 命令一起使用的安全的随机生成的证书密钥。
你也可以使用 kubeadm init --upload-certs 而无需指定证书密钥;
命令将为你生成并打印一个证书密钥。
kubeadm certs certificate-key [flags]
选项 -h, --help certificate-key 操作的帮助命令
从父命令继承的选项 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
6.7.1.1.12 - 概要 检查 kubeadm 管理的本地 PKI 中证书的到期时间。
kubeadm certs check-expiration [flags]
选项 --cert-dir string 默认值: "/etc/kubernetes/pki" 保存证书的路径 --config string kubeadm 配置文件的路径 -h, --help check-expiration 的帮助命令
继承于父命令的选项 --rootfs string [实验] 到'真实'主机根文件系统的路径。
6.7.1.1.13 - 为运行控制平面所需的所有证书生成密钥和证书签名请求(CSR)。该命令会生成部分 kubeconfig 文件,
其中 "users > user > client-key-data" 字段包含私钥数据,并为每个 kubeconfig
文件创建一个随附的 ".csr" 文件。
此命令设计用于
Kubeadm 外部 CA 模式 。
它生成你可以提交给外部证书颁发机构进行签名的 CSR。
应使用 ".crt" 作为文件扩展名将 PEM 编码的签名证书与密钥文件一起保存。
或者,对于 kubeconfig 文件,PEM 编码的签名证书应使用 base64 编码,
并添加到 "users > user > client-certificate-data" 字段。
kubeadm certs generate-csr [flags]
示例 # 以下命令将为所有控制平面证书和 kubeconfig 文件生成密钥和 CSR :
kubeadm certs generate-csr --kubeconfig-dir /tmp/etc-k8s --cert-dir /tmp/etc-k8s/pki
选项 --cert-dir string 保存证书的路径 --config string kubeadm 配置文件的路径。 -h, --help generate-csr 命令的帮助 --kubeconfig-dir string 默认值:"/etc/kubernetes" 保存 kubeconfig 文件的路径。
继承于父命令的选项 --rootfs string [实验] 到'真实'主机根文件系统的路径。
6.7.1.1.14 - 概要 此命令并非设计用来单独运行。请参阅可用子命令列表。
kubeadm certs renew [flags]
选项 从父命令继承的选项 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
6.7.1.1.15 - 概要 续订 kubeconfig 文件中嵌入的证书,供管理员 和 kubeadm 自身使用。
无论证书的到期日期如何,续订都是无条件进行的;SAN 等额外属性将基于现有文件/证书,因此无需重新提供它们。
默认情况下,续订会尝试使用由 kubeadm 管理的本地 PKI 中的证书机构;作为替代方案,
也可以使用 K8s 证书 API 进行证书续订,或者(作为最后一种选择)生成 CSR 请求。
续订后,为了使更改生效,需要重新启动控制平面组件,并最终重新分发更新的证书,以防证书文件在其他地方使用。
kubeadm certs renew admin.conf [flags]
选项 --cert-dir string 默认值:"/etc/kubernetes/pki" 保存证书的路径。 --config string kubeadm 配置文件的路径。 --csr-dir string CSR 和私钥的输出路径 --csr-only 创建 CSR 而不是生成证书 -h, --help admin.conf 子操作的帮助命令 --kubeconfig string Default: "/etc/kubernetes/admin.conf" 与集群通信时使用的 kubeconfig 文件。
如果未设置该参数,则可以在一组标准位置中搜索现有的 kubeconfig 文件。 --use-api 使用 Kubernetes 证书 API 续订证书
从父命令继承的选项 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
6.7.1.1.16 - 概要 续订运行控制平面所需的所有已知证书。续订是无条件进行的,与到期日期无关。续订也可以单独运行以进行更多控制。
kubeadm certs renew all [flags]
选项 --cert-dir string 默认值:"/etc/kubernetes/pki" 存储证书的路径。 --config string kubeadm 配置文件的路径。 --csr-dir string 输出 CSR 和私钥的路径 --csr-only 创建 CSR 而不是生成证书 -h, --help all 操作的帮助命令 --kubeconfig string 默认值:"/etc/kubernetes/admin.conf" 与集群通信时使用的 kubeconfig 文件。
如果未设置该参数,则可以在一组标准位置中搜索现有的 kubeconfig 文件。 --use-api 使用 Kubernetes 证书 API 续订证书
从父命令继承的选项 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
6.7.1.1.17 - 概要 续订 apiserver 用于访问 etcd 的证书。
无论证书的到期日期如何,续订都会无条件地进行;SAN 等额外属性将基于现有文件/证书,因此无需重新提供它们。
默认情况下,续订尝试使用在 kubeadm 所管理的本地 PKI 中的证书颁发机构;作为替代方案,
可以使用 K8s 证书 API 进行证书更新,或者作为最后一个选择来生成 CSR 请求。
续订后,为了使更改生效,需要重新启动控制平面组件,并最终重新分发更新的证书,以防文件在其他地方使用。
kubeadm certs renew apiserver-etcd-client [flags]
选项 --cert-dir string 默认值:"/etc/kubernetes/pki" 存储证书的路径。 --config string kubeadm 配置文件的路径。 --csr-dir string 输出 CSR 和私钥的路径 --csr-only 创建 CSR 而不是生成证书 -h, --help apiserver-etcd-client 操作的帮助命令 --kubeconfig string 默认值:"/etc/kubernetes/admin.conf" 与集群通信时使用的 kubeconfig 文件。
如果未设置该参数,则可以在一组标准位置中搜索现有的 kubeconfig 文件。 --use-api 使用 Kubernetes 证书 API 续订证书
从父命令继承的选项 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
6.7.1.1.18 - 概要 续订 apiserver 用于连接 kubelet 的证书。
无论证书的到期日期如何,续订都会无条件地进行;SAN 等额外属性将基于现有文件/证书,因此无需重新提供它们。
默认情况下,续订尝试使用位于 kubeadm 所管理的本地 PKI 中的证书颁发机构;作为替代方案,
也可能调用 K8s 证书 API 进行证书更新;亦或者,作为最后一个选择,生成 CSR 请求。
续订后,为了使更改生效,需要重新启动控制平面组件,并最终重新分发更新的证书,以防文件在其他地方使用。
kubeadm certs renew apiserver-kubelet-client [flags]
选项 --cert-dir string 默认值:"/etc/kubernetes/pki" 存储证书的路径。 --config string kubeadm 配置文件的路径。 --csr-dir string 输出 CSR 和私钥的路径 --csr-only 创建 CSR 而不是生成证书 -h, --help apiserver-kubelet-client 操作的帮助命令 --kubeconfig string 默认值:"/etc/kubernetes/admin.conf" 与集群通信时使用的 kubeconfig 文件。
如果未设置该参数,则可以在一组标准位置中搜索现有的 kubeconfig 文件。 --use-api 使用 Kubernetes 证书 API 续订证书
从父命令继承的选项 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
6.7.1.1.19 - 概要 续订用于提供 Kubernetes API 的证书。
无论证书的到期日期如何,续订都会无条件地进行;SAN 等额外属性将基于现有文件/证书,因此无需重新提供它们。
默认情况下,续订尝试在 kubeadm 管理的本地 PKI 中使用证书颁发机构;作为替代方案,
可以使用 K8s 证书 API 进行证书更新,或者作为最后一个选择来生成 CSR 请求。
续订后,为了使更改生效,需要重新启动控制平面组件,并最终重新分发更新的证书,以防文件在其他地方使用。
kubeadm certs renew apiserver [flags]
选项 --cert-dir string 默认值:"/etc/kubernetes/pki" 保存证书的路径。 --config string kubeadm 配置文件的路径。 --csr-dir string CSR 和私钥的输出路径 --csr-only 创建 CSR 而不是生成证书 -h, --help apiserver 子操作的帮助命令 --kubeconfig string 默认值:"/etc/kubernetes/admin.conf" 与集群通信时使用的 kubeconfig 文件。
如果未设置该参数,则可以在一组标准位置中搜索现有的 kubeconfig 文件。 --use-api 使用 Kubernetes 证书 API 续订证书
从父命令继承的选项 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
6.7.1.1.20 - 概要 续订 kubeconfig 文件中嵌入的证书,以供控制器管理器(Controller Manager)使用。
续订无条件地进行,与证书的到期日期无关;SAN 等额外属性将基于现有的文件/证书,因此无需重新提供它们。
默认情况下,续订会尝试使用 kubeadm 管理的本地 PKI 中的证书颁发机构;作为替代方案,
可以使用 K8s 证书 API 进行证书续订;亦或者,作为最后一种选择,生成 CSR 请求。
续订后,为了使更改生效,需要重新启动控制平面组件,并最终重新分发更新的证书,以防文件在其他地方使用。
kubeadm alpha renew controller-manager.conf [flags]
选项 --cert-dir string 默认值:"/etc/kubernetes/pki" 保存证书的路径。 --config string kubeadm 配置文件的路径。 --csr-dir string CSR 和私钥的输出路径 --csr-only 创建 CSR 而不是生成证书 -h, --help controller-manager.conf 操作的帮助命令 --kubeconfig string 默认值:"/etc/kubernetes/admin.conf" 与集群通信时使用的 kubeconfig 文件。
如果未设置该参数,则可以在一组标准位置中搜索现有的 kubeconfig 文件。 --use-api 使用 Kubernetes 证书 API 续订证书
从父命令继承的选项 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
6.7.1.1.21 - 概要 续订存活态探针的证书,用于对 etcd 执行健康检查。
无论证书的到期日期如何,续订都是无条件进行的;SAN 等额外属性将基于现有文件/证书,因此无需重新提供它们。
默认情况下,续订会尝试使用由 kubeadm 管理的本地 PKI 中的证书机构;作为替代方案,
也可以使用 K8s certificate API 进行证书续订,或者(作为最后一种选择)生成 CSR 请求。
续订后,为了使更改生效,需要重新启动控制平面组件,并最终重新分发更新的证书,以防证书文件在其他地方使用。
kubeadm certs renew etcd-healthcheck-client [flags]
选项 --cert-dir string 默认值:"/etc/kubernetes/pki" 保存证书的路径。 --config string kubeadm 配置文件的路径。 --csr-dir string CSR 和私钥的输出路径 --csr-only 创建 CSR 而不是生成证书 -h, --help etcd-healthcheck-client 操作的帮助命令 --kubeconfig string 默认值:"/etc/kubernetes/admin.conf" 与集群通信时使用的 kubeconfig 文件。
如果未设置该参数,则可以在一组标准位置中搜索现有的 kubeconfig 文件。 --use-api 使用 Kubernetes 证书 API 续订证书
从父命令继承的选项 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
6.7.1.1.22 - 概要 续订 etcd 节点间用来相互通信的证书。
无论证书的到期日期如何,续订都是无条件进行的;SAN 等额外属性将基于现有文件/证书,因此无需重新提供它们。
默认情况下,续订会尝试使用由 kubeadm 管理的本地 PKI 中的证书机构;
作为替代方案,也可以使用 K8s certificate API 进行证书续订,或者(作为最后一种选择)生成 CSR 请求。
续订后,为了使更改生效,需要重新启动控制平面组件,并最终重新分发更新的证书,以防证书文件在其他地方使用。
kubeadm certs renew etcd-peer [flags]
选项 --cert-dir string 默认值:"/etc/kubernetes/pki" 保存证书的路径。 --config string kubeadm 配置文件的路径。 --csr-dir string CSR 和私钥的输出路径 --csr-only 创建 CSR 而不是生成证书 -h, --help etcd-peer 操作的帮助命令 --kubeconfig string 默认值:"/etc/kubernetes/admin.conf" 与集群通信时使用的 kubeconfig 文件。
如果未设置该参数,则可以在一组标准位置中搜索现有的 kubeconfig 文件。 --use-api 使用 Kubernetes 证书 API 续订证书
从父命令继承的选项 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
6.7.1.1.23 - 概要 续订用于提供 etcd 服务的证书。
续订无条件地进行,与证书的到期日期无关;SAN 等额外属性将基于现有的文件/证书,因此无需重新提供它们。
默认情况下,续订会尝试在 kubeadm 管理的本地 PKI 中使用证书颁发机构;作为替代方案,
可以使用 K8s 证书 API 进行证书续订,或者作为最后一种选择来生成 CSR 请求。
续订后,为了使更改生效,需要重新启动控制平面组件,并最终重新分发更新的证书,以防文件在其他地方使用。
kubeadm certs renew etcd-server [flags]
选项 --cert-dir string 默认值:"/etc/kubernetes/pki" 保存证书的路径。 --config string kubeadm 配置文件的路径。 --csr-dir string CSR 和私钥的输出路径 --csr-only 创建 CSR 而不是生成证书 -h, --help etcd-server 操作的帮助命令 --kubeconfig string 默认值:"/etc/kubernetes/admin.conf" 与集群通信时使用的 kubeconfig 文件。
如果未设置该参数,则可以在一组标准位置中搜索现有的 kubeconfig 文件。 --use-api 使用 Kubernetes 证书 API 续订证书
从父命令继承的选项 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
6.7.1.1.24 - 概要 为前端代理客户端续订证书。
无论证书的到期日期如何,续订都会无条件地进行;SAN 等额外属性将基于现有文件/证书,因此无需重新提供它们。
默认情况下,续订尝试使用位于 kubeadm 所管理的本地 PKI 中的证书颁发机构;作为替代方案,
也可以使用 K8s 证书 API 进行证书续订;亦或者,作为最后一种方案,生成 CSR 请求。
续订后,为了使更改生效,需要重新启动控制平面组件,并最终重新分发更新的证书,以防文件在其他地方使用。
kubeadm certs renew front-proxy-client [flags]
选项 --cert-dir string 默认值:"/etc/kubernetes/pki" 存储证书的路径。 --config string kubeadm 配置文件的路径。 --csr-dir string 输出 CSR 和私钥的路径 --csr-only 创建 CSR 而不是生成证书 -h, --help front-proxy-client 操作的帮助命令 --kubeconfig string 默认值:"/etc/kubernetes/admin.conf" 与集群通信时使用的 kubeconfig 文件。
如果未设置该参数,则可以在一组标准位置中搜索现有的 kubeconfig 文件。 --use-api 使用 Kubernetes 证书 API 续订证书
从父命令继承的选项 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
6.7.1.1.25 - 概要 续订 kubeconfig 文件中嵌入的证书,以供调度管理器使用。
续订无条件地进行,与证书的到期日期无关;SAN 等额外属性将基于现有的文件/证书,因此无需重新提供它们。
默认情况下,续订会尝试使用在 kubeadm 所管理的本地 PKI 中的证书颁发机构;作为替代方案,
也可以使用 K8s 证书 API 进行证书续订;亦或者,作为最后一种选择,生成 CSR 请求。
续订后,为了使更改生效,需要重新启动控制平面组件,并最终重新分发更新的证书,以防文件在其他地方使用。
kubeadm certs renew scheduler.conf [flags]
选项 --cert-dir string 默认值:"/etc/kubernetes/pki" 保存证书的路径。 --config string kubeadm 配置文件的路径。 --csr-dir string CSR 和私钥的输出路径 --csr-only 创建 CSR 而不是生成证书 -h, --help scheduler.conf 操作的帮助命令 --kubeconfig string 默认值:"/etc/kubernetes/admin.conf" 与集群通信时使用的 kubeconfig 文件。
如果未设置该参数,则可以在一组标准位置中搜索现有的 kubeconfig 文件。 --use-api 使用 Kubernetes 证书 API 续订证书
从父命令继承的选项 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
6.7.1.1.26 - 概要 为指定的 shell(bash 或 zsh)输出 shell 自动补全代码。
必须激活 shell 代码以提供交互式 kubeadm 命令补全。这可以通过加载 .bash_profile 文件完成。
注意: 此功能依赖于 bash-completion 框架。
在 Mac 上使用 homebrew 安装:
brew install bash-completion
安装后,必须激活 bash_completion。这可以通过在 .bash_profile 文件中添加下面的命令行来完成
source $(brew --prefix)/etc/bash_completion
如果在 Linux 上没有安装 bash-completion,请通过您的发行版的包管理器安装 bash-completion 软件包。
zsh 用户注意事项:[1] zsh 自动补全仅在 >=v5.2 及以上版本中支持。
kubeadm completion SHELL [flags]
示例 # 在 Mac 上使用 homebrew 安装 bash completion
brew install bash-completion
printf "\n# Bash completion support\nsource $(brew --prefix)/etc/bash_completion\n" >> $HOME/.bash_profile
source $HOME/.bash_profile
# 将 bash 版本的 kubeadm 自动补全代码加载到当前 shell 中
source <(kubeadm completion bash)
# 将 bash 自动补全完成代码写入文件并且从 .bash_profile 文件加载它
printf "\n# Kubeadm shell completion\nsource '$HOME/.kube/kubeadm_completion.bash.inc'\n" >> $HOME/.bash_profile
source $HOME/.bash_profile
# 将 zsh 版本的 kubeadm 自动补全代码加载到当前 shell 中
source <(kubeadm completion zsh)
选项 -h, --help completion 操作的帮助命令
从父命令继承的选项 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
6.7.1.1.27 - 概要 kube-system 命名空间里有一个名为 "kubeadm-config" 的 ConfigMap,kubeadm 用它来存储有关集群的内部配置。
kubeadm CLI v1.8.0+ 通过一个配置自动创建该 ConfigMap,这个配置是和 'kubeadm init' 共用的。
但是您如果使用 kubeadm v1.7.x 或更低的版本初始化集群,那么必须使用 'config upload' 命令创建该 ConfigMap。
这是必要的操作,目的是使 'kubeadm upgrade' 能够正确地配置升级后的集群。
kubeadm config [flags]
选项 -h, --help config 操作的帮助命令 --kubeconfig string 默认值:"/etc/kubernetes/admin.conf" 用于和集群通信的 kubeconfig 文件。如果它没有被设置,那么 kubeadm 将会搜索一个已经存在于标准路径的 kubeconfig 文件
从父命令继承的选项 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
6.7.1.1.28 - 概要 与 kubeadm 使用的容器镜像交互。
kubeadm config images [flags]
选项 从父命令继承的选项 --kubeconfig string 默认值:"/etc/kubernetes/admin.conf" 用于和集群通信的 kubeconfig 文件。如果它没有被设置,那么 kubeadm 将会搜索一个已经存在于标准路径的 kubeconfig 文件。 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
6.7.1.1.29 - 概要 打印 kubeadm 要使用的镜像列表。配置文件用于自定义任何镜像或镜像存储库。
kubeadm config images list [flags]
选项 --allow-missing-template-keys 默认值:true 如果设置为 true,则在模板中缺少字段或哈希表的键时忽略模板中的任何错误。
仅适用于 golang 和 jsonpath 输出格式。 -o, --experimental-output string 默认值:"text" 输出格式:text|json|yaml|go-template|go-template-file|template|templatefile|jsonpath|jsonpath-as-json|jsonpath-file 其中之一 --config string kubeadm 配置文件的路径。 --feature-gates string 一组键值对(key=value),用于描述各种特征。选项是: Auditing=true|false (ALPHA - 默认=false) CoreDNS=true|false (默认=true) DynamicKubeletConfig=true|false (BETA - 默认=false) -h, --help list 操作的帮助命令 --image-repository string 默认值:"k8s.gcr.io" 选择要从中拉取控制平面镜像的容器仓库 --kubernetes-version string 默认值:"stable-1" 为控制平面选择一个特定的 Kubernetes 版本
从父命令继承的选项 --kubeconfig string 默认值:"/etc/kubernetes/admin.conf" 用于和集群通信的 kubeconfig 文件。如果它没有被设置,那么 kubeadm 将会搜索一个已经存在于标准路径的 kubeconfig 文件。 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
6.7.1.1.30 - 概要 拉取 kubeadm 使用的镜像。
kubeadm config images pull [flags]
选项 --config string kubeadm 配置文件的路径。 --cri-socket string 要连接的 CRI 套接字的路径。如果为空,则 kubeadm 将尝试自动检测此值;仅当安装了多个 CRI 或具有非标准 CRI 插槽时,才使用此选项。 --feature-gates string 一系列键值对(key=value),用于描述各种特征。可选项是: IPv6DualStack=true|false (ALPHA - 默认值=false) -h, --help pull 操作的帮助命令 --image-repository string 默认值:"k8s.gcr.io" 选择用于拉取控制平面镜像的容器仓库 --kubernetes-version string 默认值:"stable-1" 为控制平面选择一个特定的 Kubernetes 版本。
从父命令继承的选项 --kubeconfig string 默认值:"/etc/kubernetes/admin.conf" 用于和集群通信的 kubeconfig 文件。如果它没有被设置,那么 kubeadm 将会搜索一个已经存在于标准路径的 kubeconfig 文件。 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
6.7.1.1.31 - 概要 此命令允许您在 CLI 工具中将本地旧版本的配置对象转换为最新支持的版本,而无需变更集群中的任何内容。在此版本的 kubeadm 中,支持以下 API 版本:
因此,无论您在此处传递 --old-config 参数的版本是什么,当写入到 stdout 或 --new-config (如果已指定)时,
都会读取、反序列化、默认、转换、验证和重新序列化 API 对象。
换句话说,如果您将此文件传递给 "kubeadm init",则该命令的输出就是 kubeadm 实际上在内部读取的内容。
kubeadm config migrate [flags]
选项 -h, --help migrate 操作的帮助信息 --new-config string 使用新的 API 版本生成的 kubeadm 配置文件的路径。这个路径是可选的。如果没有指定,输出将被写到 stdout。 --old-config string 使用旧 API 版本且应转换的 kubeadm 配置文件的路径。此参数是必需的。
从父命令继承的选项 --kubeconfig string 默认值:"/etc/kubernetes/admin.conf" 用于和集群通信的 kubeconfig 文件。如果未设置,那么 kubeadm 将会搜索一个已经存在于标准路径的 kubeconfig 文件。 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
6.7.1.1.32 - 概要 此命令显示所提供子命令的配置。
有关详细信息,请参阅:https://godoc.org/k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1beta2
kubeadm config print [flags]
选项 从父命令继承的选项 --kubeconfig string 默认值:"/etc/kubernetes/admin.conf" 用于和集群通信的 kubeconfig 文件。如果它没有被设置,那么 kubeadm 将会搜索一个已经存在于标准路径的 kubeconfig 文件。 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
6.7.1.1.33 - 概要 此命令打印对象,例如用于 'kubeadm init' 的默认 init 配置对象。
请注意,Bootstrap Token 字段之类的敏感值已替换为 {"abcdef.0123456789abcdef" "" "nil" <nil> [] []} 之类的占位符值以通过验证,但不执行创建令牌的实际计算。
kubeadm config print init-defaults [flags]
选项 --component-configs stringSlice 组件配置 API 对象的逗号分隔列表,打印其默认值。可用值:[KubeProxyConfiguration KubeletConfiguration]。如果未设置此参数,则不会打印任何组件配置。 -h, --help init-defaults 操作的帮助命令
从父命令继承的选项 --kubeconfig string 默认值:"/etc/kubernetes/admin.conf" 与集群通信时使用的 kubeconfig 文件。如果未设置该参数,则可以在一组标准位置中搜索现有的 kubeconfig 文件。 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
6.7.1.1.34 - 概要 此命令打印对象,例如用于 'kubeadm join' 的默认 join 配置对象。
请注意,诸如启动引导令牌字段之类的敏感值已替换为 {"abcdef.0123456789abcdef" "" "nil" <nil> [] []}
之类的占位符值以通过验证,但不执行创建令牌的实际计算。
kubeadm config print join-defaults [flags]
选项 --component-configs stringSlice 组件配置 API 对象的逗号分隔列表,打印其默认值。可用值:[KubeProxyConfiguration KubeletConfiguration]。如果未设置此参数,则不会打印任何组件配置。 -h, --help join-defaults 操作的帮助命令
从父命令继承的选项 --kubeconfig string 默认值:"/etc/kubernetes/admin.conf" 与集群通信时使用的 kubeconfig 文件。如果未设置该参数,则可以在一组标准位置中搜索现有的 kubeconfig 文件。 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
6.7.1.1.35 - 概要 使用此命令,可以查看 kubeadm 配置的集群中的 ConfigMap。
该配置位于 "kube-system" 命名空间中的名为 "kubeadm-config" 的 ConfigMap 中。
kubeadm config view [flags]
选项 继承于父命令的选项 --kubeconfig string 默认值:"/etc/kubernetes/admin.conf" 用于和集群通信的 KubeConfig 文件。如果未设置,那么 kubeadm 将会搜索一个已经存在于标准路径的 KubeConfig 文件。 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
6.7.1.1.36 - 概要 运行此命令来搭建 Kubernetes 控制平面节点。
"init" 命令执行以下阶段:
preflight Run pre-flight checks
certs Certificate generation
/ca Generate the self-signed Kubernetes CA to provision identities for other Kubernetes components
/apiserver Generate the certificate for serving the Kubernetes API
/apiserver-kubelet-client Generate the certificate for the API server to connect to kubelet
/front-proxy-ca Generate the self-signed CA to provision identities for front proxy
/front-proxy-client Generate the certificate for the front proxy client
/etcd-ca Generate the self-signed CA to provision identities for etcd
/etcd-server Generate the certificate for serving etcd
/etcd-peer Generate the certificate for etcd nodes to communicate with each other
/etcd-healthcheck-client Generate the certificate for liveness probes to healthcheck etcd
/apiserver-etcd-client Generate the certificate the apiserver uses to access etcd
/sa Generate a private key for signing service account tokens along with its public key
kubeconfig Generate all kubeconfig files necessary to establish the control plane and the admin kubeconfig file
/admin Generate a kubeconfig file for the admin to use and for kubeadm itself
/kubelet Generate a kubeconfig file for the kubelet to use *only* for cluster bootstrapping purposes
/controller-manager Generate a kubeconfig file for the controller manager to use
/scheduler Generate a kubeconfig file for the scheduler to use
kubelet-start Write kubelet settings and (re)start the kubelet
control-plane Generate all static Pod manifest files necessary to establish the control plane
/apiserver Generates the kube-apiserver static Pod manifest
/controller-manager Generates the kube-controller-manager static Pod manifest
/scheduler Generates the kube-scheduler static Pod manifest
etcd Generate static Pod manifest file for local etcd
/local Generate the static Pod manifest file for a local, single-node local etcd instance
upload-config Upload the kubeadm and kubelet configuration to a ConfigMap
/kubeadm Upload the kubeadm ClusterConfiguration to a ConfigMap
/kubelet Upload the kubelet component config to a ConfigMap
upload-certs Upload certificates to kubeadm-certs
mark-control-plane Mark a node as a control-plane
bootstrap-token Generates bootstrap tokens used to join a node to a cluster
kubelet-finalize Updates settings relevant to the kubelet after TLS bootstrap
/experimental-cert-rotation Enable kubelet client certificate rotation
addon Install required addons for passing Conformance tests
/coredns Install the CoreDNS addon to a Kubernetes cluster
/kube-proxy Install the kube-proxy addon to a Kubernetes cluster
kubeadm init [flags]
选项 --apiserver-advertise-address string API 服务器所公布的其正在监听的 IP 地址。如果未设置,则使用默认网络接口。 --apiserver-bind-port int32 默认值:6443 API 服务器绑定的端口。 --apiserver-cert-extra-sans stringSlice 用于 API Server 服务证书的可选附加主题备用名称(SAN)。可以是 IP 地址和 DNS 名称。 --cert-dir string 默认值:"/etc/kubernetes/pki" 保存和存储证书的路径。 --certificate-key string 用于加密 kubeadm-certs Secret 中的控制平面证书的密钥。 --config string kubeadm 配置文件的路径。 --control-plane-endpoint string 为控制平面指定一个稳定的 IP 地址或 DNS 名称。 --cri-socket string 要连接的 CRI 套接字的路径。如果为空,则 kubeadm 将尝试自动检测此值;仅当安装了多个 CRI 或具有非标准 CRI 插槽时,才使用此选项。 --dry-run 不要应用任何更改;只是输出将要执行的操作。 --experimental-patches string 包含名为 "target[suffix][+patchtype].extension" 的文件的目录路径。
例如,"kube-apiserver0+merge.yaml" 或仅仅是 "etcd.json"。
"patchtype" 可以是 "strategic"、"merge" 或 "json" 之一,并且它们与 kubectl 支持的补丁格式匹配。
默认的 "patchtype" 为 "strategic"。 "extension" 必须为 "json" 或 "yaml"。
"suffix" 是一个可选字符串,可用于确定首先按字母顺序应用哪些补丁。 --feature-gates string 一组用来描述各种功能特性的键值(key=value)对。选项是: IPv6DualStack=true|false (ALPHA - default=false) -h, --help init 操作的帮助命令 --ignore-preflight-errors stringSlice 错误将显示为警告的检查列表;例如:'IsPrivilegedUser,Swap'。取值为 'all' 时将忽略检查中的所有错误。 --image-repository string 默认值:"k8s.gcr.io" 选择用于拉取控制平面镜像的容器仓库 --kubernetes-version string 默认值:"stable-1" 为控制平面选择一个特定的 Kubernetes 版本。 --node-name string 指定节点的名称。 --pod-network-cidr string 指明 pod 网络可以使用的 IP 地址段。如果设置了这个参数,控制平面将会为每一个节点自动分配 CIDRs。 --service-cidr string 默认值:"10.96.0.0/12" 为服务的虚拟 IP 地址另外指定 IP 地址段 --service-dns-domain string 默认值:"cluster.local" 为服务另外指定域名,例如:"myorg.internal"。 --skip-certificate-key-print 不要打印用于加密控制平面证书的密钥。 --skip-phases stringSlice 要跳过的阶段列表 --skip-token-print 跳过打印 'kubeadm init' 生成的默认引导令牌。 --token string 这个令牌用于建立控制平面节点与工作节点间的双向通信。格式为 [a-z0-9]{6}\.[a-z0-9]{16} - 示例:abcdef.0123456789abcdef --token-ttl duration 默认值:24h0m0s 令牌被自动删除之前的持续时间(例如 1 s,2 m,3 h)。如果设置为 '0',则令牌将永不过期 --upload-certs 将控制平面证书上传到 kubeadm-certs Secret。
从父命令继承的选项 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
6.7.1.1.37 - 概要 使用此命令可以调用 init 工作流程的单个阶段
选项 继承于父命令的选择项 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
6.7.1.1.38 - 概要 此命令并非设计用来单独运行。请参阅可用子命令列表。
kubeadm init phase addon [flags]
选项 继承于父命令的选项 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
6.7.1.1.39 - 概要 安装所有插件(addon)
kubeadm init phase addon all [flags]
选项 --apiserver-advertise-address string API 服务器所公布的其正在监听的 IP 地址。如果未设置,则将使用默认网络接口。 --apiserver-bind-port int32 默认值:6443 API 服务器绑定的端口。 --config string kubeadm 配置文件的路径。 --control-plane-endpoint string 为控制平面指定一个稳定的 IP 地址或 DNS 名称。 --feature-gates string 一组键值对(key=value),描述了各种特征。选项包括: IPv6DualStack=true|false (ALPHA - 默认值=false) -h, --help --image-repository string 默认值:"k8s.gcr.io" 选择用于拉取控制平面镜像的容器仓库 --kubeconfig string 默认值:"/etc/kubernetes/admin.conf" 与集群通信时使用的 kubeconfig 文件。如果未设置该参数,则可以在一组标准位置中搜索现有的 kubeconfig 文件。 --kubernetes-version string 默认值:"stable-1" 为控制平面选择特定的 Kubernetes 版本。 --pod-network-cidr string 指定 Pod 网络的 IP 地址范围。如果已设置,控制平面将自动为每个节点分配 CIDR。 --service-cidr string 默认值:"10.96.0.0/12" 为服务 VIP 使用 IP 地址的其他范围。 --service-dns-domain string 默认值:"cluster.local" 为服务使用其他域名,例如 "myorg.internal"。
继承于父命令的选项 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
6.7.1.1.40 - 概要 通过 API 服务器安装 CoreDNS 附加组件。请注意,即使 DNS 服务器已部署,在安装 CNI 之前 DNS 服务器不会被调度执行。
kubeadm init phase addon coredns [flags]
选项 --config string kubeadm 配置文件的路径。 --feature-gates string 一组用来描述各种功能特性的键值(key=value)对。选项是: IPv6DualStack=true|false (ALPHA - 默认值=false) -h, --help coredns 操作的帮助命令 --image-repository string 默认值:"k8s.gcr.io" 选择用于拉取控制平面镜像的容器仓库 --kubeconfig string 默认值:"/etc/kubernetes/admin.conf" 与集群通信时使用的 kubeconfig 文件。如果未设置该参数,则可以在一组标准位置中搜索现有的 kubeconfig 文件。 --kubernetes-version string 默认值:"stable-1" 为控制平面选择特定的 Kubernetes 版本。 --service-cidr string 默认值:"10.96.0.0/12" 为服务 VIP 选择 IP 地址范围。 --service-dns-domain string 默认值:"cluster.local" 服务使用其它的域名,例如:"myorg.internal"。
继承于父命令的选项 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
6.7.1.1.41 - 概要 通过 API 服务器安装 kube-proxy 附加组件。
kubeadm init phase addon kube-proxy [flags]
选项 --apiserver-advertise-address string API 服务器所公布的其正在监听的 IP 地址。如果未设置,则将使用默认网络接口。 --apiserver-bind-port int32 默认值: 6443 API 服务器绑定的端口。 --config string kubeadm 配置文件的路径。 --control-plane-endpoint string 为控制平面指定一个稳定的 IP 地址或 DNS 名称。 -h, --help kube-proxy 操作的帮助命令 --image-repository string 默认值:"k8s.gcr.io" 选择用于拉取控制平面镜像的容器仓库 --kubeconfig string 默认值:"/etc/kubernetes/admin.conf" 与集群通信时使用的 kubeconfig 文件。如果未设置该参数,则可以在一组标准位置中搜索现有的 kubeconfig 文件。 --kubernetes-version string 默认值:"stable-1" 为控制平面选择特定的 Kubernetes 版本。 --pod-network-cidr string 指定 Pod 网络的 IP 地址范围。如果已设置,控制平面将自动为每个节点分配 CIDR。
继承于父命令的选项 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
6.7.1.1.42 - 概要 启动引导令牌(bootstrap token)用于在即将加入集群的节点和控制平面节点之间建立双向信任。
该命令使启动引导令牌(bootstrap token)所需的所有配置生效,然后创建初始令牌。
kubeadm init phase bootstrap-token [flags]
示例 # 进行所有引导令牌配置,并创建一个初始令牌,功能上与 kubeadm init 生成的令牌等效。
kubeadm init phase bootstrap-token
选项 --config string kubeadm 配置文件的路径。 -h, --help bootstrap-token 操作的帮助命令 --kubeconfig string 默认值:"/etc/kubernetes/admin.conf" 用于和集群通信的 kubeconfig 文件。如果它没有被设置,那么 kubeadm 将会搜索一个已经存在于标准路径的 kubeconfig 文件。 --skip-token-print 跳过打印 'kubeadm init' 生成的默认引导令牌。
继承于父命令的选项 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
6.7.1.1.43 - 概要 此命令并非设计用来单独运行。请参阅可用子命令列表。
kubeadm init phase certs [flags]
选项 从父指令中继承的选项 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
6.7.1.1.44 - 概要 生成所有证书
kubeadm init phase certs all [flags]
选项 --apiserver-advertise-address string API 服务器所公布的其正在监听的 IP 地址。如果未设置,将使用默认网络接口。 --apiserver-cert-extra-sans stringSlice 用于 API 服务器服务证书的可选额外替代名称(SAN)。可以同时使用 IP 地址和 DNS 名称。 --cert-dir string 默认值:"/etc/kubernetes/pki" 证书的存储路径。 --config string kubeadm 配置文件的路径。 --control-plane-endpoint string 为控制平面指定一个稳定的 IP 地址或 DNS 名称。 -h, --help all 操作的帮助命令 --kubernetes-version string 默认值:"stable-1" 为控制平面选择特定的 Kubernetes 版本。 --service-cidr string 默认值:"10.96.0.0/12" VIP 服务使用其它的 IP 地址范围。 --service-dns-domain string 默认值:"cluster.local" 服务使用其它的域名,例如:"myorg.internal"。
继承于父命令的选项 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
6.7.1.1.45 - 概要 生成 apiserver 用于访问 etcd 的证书,并将其保存到 apiserver-etcd-client.cert 和 apiserver-etcd-client.key 文件中。
如果两个文件都已存在,则 kubeadm 将跳过生成步骤,使用现有文件。
Alpha 免责声明:此命令当前为 Alpha 功能。
kubeadm init phase certs apiserver-etcd-client [flags]
选项 --cert-dir string 默认值:"/etc/kubernetes/pki" 证书的存储路径。 --config string kubeadm 配置文件的路径。 -h, --help apiserver-etcd-client 操作的帮助命令 --kubernetes-version string 默认值:"stable-1" 为控制平面指定特定的 Kubernetes 版本。
继承于父命令的选项 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
6.7.1.1.46 - 概要 生成供 API 服务器连接 kubelet 的证书,并将其保存到 apiserver-kubelet-client.cert 和 apiserver-kubelet-client.key 文件中。
如果两个文件都已存在,则 kubeadm 将跳过生成步骤,使用现有文件。
Alpha 免责声明:此命令当前为 Alpha 功能。
kubeadm init phase certs apiserver-kubelet-client [flags]
选项 --cert-dir string 默认值:"/etc/kubernetes/pki" 存储证书的路径。 --config string kubeadm 配置文件路径。 -h, --help apiserver-kubelet-client 操作的帮助命令 --kubernetes-version string 默认值:"stable-1" 为控制平面指定特定的 Kubernetes 版本。
继承于父命令的选项 --rootfs string [实验] 指向宿主机上的 '实际' 根文件系统的路径。
6.7.1.1.47 - 概要 生成用于服务 Kubernetes API 的证书,并将其保存到 apiserver.cert 和 apiserver.key 文件中。
默认 SAN 是 kubernetes、kubernetes.default、kubernetes.default.svc、kubernetes.default.svc.cluster.local、10.96.0.1、127.0.0.1。
如果两个文件都已存在,则 kubeadm 将跳过生成步骤,使用现有文件。
Alpha 免责声明:此命令当前为 Alpha 功能。
kubeadm init phase certs apiserver [flags]
选项 --apiserver-advertise-address string API 服务器所公布的其正在监听的 IP 地址。如果未设置,则使用默认的网络接口。 --apiserver-cert-extra-sans stringSlice 用于 API Server 服务证书的可选附加主体备用名称(SAN)。可以是 IP 地址和 DNS 名称。 --cert-dir string 默认值:"/etc/kubernetes/pki" 证书的存储路径。 --config string kubeadm 配置文件的路径。 --control-plane-endpoint string 为控制平面指定一个稳定的 IP 地址或 DNS 名称。 -h, --help apiserver 操作的帮助命令 --kubernetes-version string 默认值:"stable-1" 为控制平面指定特定的 Kubernetes 版本。 --service-cidr string 默认值:"10.96.0.0/12" 指定服务 VIP 可使用的其他 IP 地址段。 --service-dns-domain string 默认值:"cluster.local" 为服务使用其他域名,例如 "myorg.internal"。
继承于父命令的选项 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
6.7.1.1.48 - 概要 生成自签名的 Kubernetes CA 以提供其他 Kubernetes 组件的身份,并将其保存到 ca.cert 和 ca.key 文件中。
如果两个文件都已存在,则 kubeadm 将跳过生成步骤,使用现有文件。
Alpha 免责声明:此命令当前为 Alpha 功能。
kubeadm init phase certs ca [flags]
选项 --cert-dir string 默认值:"/etc/kubernetes/pki" 证书的存储路径。 --config string kubeadm 配置文件的路径。 -h, --help ca 操作的帮助命令 --kubernetes-version string 默认值:"stable-1" 为控制平面选择特定的 Kubernetes 版本。
继承于父命令的选项 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
6.7.1.1.49 - 概要 生成用于为 etcd 设置身份的自签名 CA,并将其保存到 etcd/ca.cert 和 etcd/ca.key 文件中。
如果两个文件都已存在,则 kubeadm 将跳过生成步骤,使用现有文件。
Alpha 免责声明:此命令当前为 Alpha 功能。
kubeadm init phase certs etcd-ca [flags]
选项 --cert-dir string 默认值:"/etc/kubernetes/pki" 证书的存储路径。 --config string kubeadm 配置文件的路径。 -h, --help etcd-ca 操作的帮助命令 --kubernetes-version string 默认值:"stable-1" 为控制平面选择特定的 Kubernetes 版本。
继承于父命令的选项 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
6.7.1.1.50 - 概要 生成用于 etcd 健康检查的活跃性探针的证书,并将其保存到 healthcheck-client.cert 和 etcd/healthcheck-client.key 文件中。
如果两个文件都已存在,则 kubeadm 将跳过生成步骤,使用现有文件。
Alpha 免责声明:此命令当前为 alpha 功能。
kubeadm init phase certs etcd-healthcheck-client [flags]
选项 --cert-dir string 默认值:"/etc/kubernetes/pki" 证书存储的路径。 --config string kubeadm 配置文件的路径。 -h, --help etcd-healthcheck-client 操作的帮助命令 --kubernetes-version string 默认值:"stable-1" 为控制平面选择特定的 Kubernetes 版本。
继承于父命令的选项 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
6.7.1.1.51 - 概要 生成 etcd 节点相互通信的证书,并将其保存到 etcd/peer.cert 和 etcd/peer.key 文件中。
默认 SAN 为 localhost、127.0.0.1、127.0.0.1、:: 1
如果两个文件都已存在,则 kubeadm 将跳过生成步骤,使用现有文件。
Alpha 免责声明:此命令当前为 alpha 功能。
kubeadm init phase certs etcd-peer [flags]
选项 --cert-dir string 默认值:"/etc/kubernetes/pki" 保存和存储证书的路径。 --config string kubeadm 配置文件的路径。 -h, --help etcd-peer 操作的帮助命令 --kubernetes-version string 默认值:"stable-1" 为控制平面指定特定的 Kubernetes 版本。
继承于父命令的选项 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
6.7.1.1.52 - 概要 生成用于提供 etcd 服务的证书,并将其保存到 etcd/server.cert 和 etcd/server.key 文件中。
默认 SAN 为 localhost、127.0.0.1、127.0.0.1、:: 1
如果两个文件都已存在,则 kubeadm 将跳过生成步骤,使用现有文件。
Alpha 免责声明:此命令当前为 alpha 功能。
kubeadm init phase certs etcd-server [flags]
选项 --cert-dir string 默认值:"/etc/kubernetes/pki" 保存和存储证书的路径。 --config string kubeadm 配置文件的路径。 -h, --help etcd-server 操作的帮助命令 --kubernetes-version string 默认值:"stable-1" 为控制平面指定特定的 Kubernetes 版本。
继承于父命令的选项 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
6.7.1.1.53 - 概要 生成自签名 CA 来提供前端代理的身份,并将其保存到 front-proxy-ca.cert 和 front-proxy-ca.key 文件中。
如果两个文件都已存在,kubeadm 将跳过生成步骤并将使用现有文件。
Alpha 免责声明:此命令目前是 alpha 阶段。
kubeadm init phase certs front-proxy-ca [flags]
选项 --cert-dir string 默认值:"/etc/kubernetes/pki" 存储证书的路径。 --config string kubeadm 配置文件的路径。 -h, --help front-proxy-ca 操作的帮助命令 --kubernetes-version string 默认值:"stable-1" 为控制平面选择特定的 Kubernetes 版本。
从父命令继承的选项 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
6.7.1.1.54 - 概要 为前端代理客户端生成证书,并将其保存到 front-proxy-client.cert 和 front-proxy-client.key 文件中。
如果两个文件都已存在,kubeadm 将跳过生成步骤并将使用现有文件。
Alpha 免责声明:此命令目前是 alpha 阶段。
kubeadm init phase certs front-proxy-client [flags]
选项 --cert-dir string 默认:"/etc/kubernetes/pki" 存储证书的路径。 --config string kubeadm 配置文件的路径。 -h, --help front-proxy-client 操作的帮助命令 --kubernetes-version string 默认值:"stable-1" 为控制平面选择特定的 Kubernetes 版本。
从父命令继承的选项 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
6.7.1.1.55 - 概要 生成用于签名 service account 令牌的私钥及其公钥,并将其保存到 sa.key 和 sa.pub 文件中。如果两个文件都已存在,则 kubeadm 会跳过生成步骤,而将使用现有文件。
Alpha 免责声明:此命令当前为 alpha 阶段。
kubeadm init phase certs sa [flags]
选项 --cert-dir string 默认值:"/etc/kubernetes/pki" 保存和存储证书的路径。 -h, --help sa 操作的帮助命令
继承于父命令的选项 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
6.7.1.1.56 - 概要 此命令并非设计用来单独运行。请参阅可用子命令列表。
kubeadm init phase control-plane [flags]
选项 -h, --help control-plane 操作的帮助命令
继承于父命令的选项 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
6.7.1.1.57 - 概要 生成所有的静态 Pod 清单文件
kubeadm init phase control-plane all [flags]
示例 # 为控制平面组件生成静态 Pod 清单文件,其功能等效于 kubeadm init 生成的文件。
kubeadm init phase control-plane all
# 使用从某配置文件中读取的选项为生成静态 Pod 清单文件。
kubeadm init phase control-plane all --config config.yaml
选项 --apiserver-advertise-address string API 服务器所公布的其正在监听的 IP 地址。如果未设置,将使用默认的网络接口。 --apiserver-bind-port int32 默认值:6443 API 服务器要绑定的端口。 --apiserver-extra-args mapStringString 形式为 <flagname>=<value> 的一组额外参数,用来传递给 API 服务器,
或者覆盖其默认配置值 --cert-dir string 默认值:"/etc/kubernetes/pki" 存储证书的路径。 --config string kubeadm 配置文件的路径。 --control-plane-endpoint string 为控制平面选择一个稳定的 IP 地址或者 DNS 名称。 --controller-manager-extra-args mapStringString 一组形式为 <flagname>=<value> 的额外参数,用来传递给控制管理器(Controller Manager)
或覆盖其默认设置值 --experimental-patches string 包含名为 "target[suffix][+patchtype].extension" 的文件的目录。
例如,"kube-apiserver0+merge.yaml" 或者 "etcd.json"。
"patchtype" 可以是 "strategic"、"merge" 或 "json" 之一,分别与 kubectl
所支持的 patch 格式相匹配。默认的 "patchtype" 是 "strategic"。
"extension" 必须是 "json" 或 "yaml"。
"suffix" 是一个可选的字符串,用来确定按字母顺序排序时首先应用哪些 patch。 --feature-gates string 一组用来描述各种特性门控的键值(key=value)对。选项是: IPv6DualStack=true|false (ALPHA - 默认=false) PublicKeysECDSA=true|false (ALPHA - 默认=false) -h, --help all 操作的帮助命令 --image-repository string 默认值:"k8s.gcr.io" 选择用于拉取控制平面镜像的容器仓库 --kubernetes-version string 默认值:"stable-1" 为控制平面选择指定的 Kubernetes 版本。 --pod-network-cidr string 指定 Pod 网络的 IP 地址范围。如果设置了此标志,控制平面将自动地为每个节点分配 CIDR。 --scheduler-extra-args mapStringString 一组形式为 <flagname>=<value> 的额外参数,用来传递给调度器(Scheduler)
或覆盖其默认设置值传递给调度器(scheduler)一组额外的参数或者以 <flagname>=<value> 形式覆盖其默认值。
--service-cidr string 默认值:"10.96.0.0/12" 为服务 VIP 选择 IP 地址范围。
从父指令继承的选项 --rootfs string [实验] 指向 '真实' 宿主机的根文件系统的路径。
6.7.1.1.58 - 概要 生成 kube-apiserver 静态 Pod 清单
kubeadm init phase control-plane apiserver [flags]
选项 --apiserver-advertise-address string API 服务器所公布的其正在监听的 IP 地址。如果未设置,将使用默认网络接口。 --apiserver-bind-port int32 默认值: 6443 要绑定到 API 服务器的端口。 --apiserver-extra-args mapStringString 一组 <flagname>=<value> 形式的额外参数,用来传递给 API 服务器
或者覆盖其默认参数配置 --cert-dir string 默认值:"/etc/kubernetes/pki" 保存和存储证书的路径。 --config string kubeadm 配置文件的路径。 --control-plane-endpoint string 为控制平面指定一个稳定的 IP 地址或 DNS 名称。 包含名为 "target[suffix][+patchtype].extension" 的文件的目录。
例如,"kube-apiserver0+merge.yaml" 或者 "etcd.json"。
"patchtype" 可以是 "strategic"、"merge" 或 "json" 之一,分别与 kubectl
所支持的 patch 格式相匹配。默认的 "patchtype" 是 "strategic"。
"extension" 必须是 "json" 或 "yaml"。
"suffix" 是一个可选的字符串,用来确定按字母顺序排序时首先应用哪些 patch。 --feature-gates string 一组键值对,用于描述各种功能特性的特性门控。选项是: IPv6DualStack=true|false (ALPHA - 默认=false) PublicKeysECDSA=true|false (ALPHA - 默认=false) -h, --help apiserver 操作的帮助命令 --image-repository string 默认值:"k8s.gcr.io" 选择要从中拉取控制平面镜像的容器仓库 --kubernetes-version string 默认值:"stable-1" 为控制平面选择特定的 Kubernetes 版本 --service-cidr string 默认值:"10.96.0.0/12" 指定服务 VIP 使用 IP 地址的其他范围。
继承于父命令的选项 --rootfs string [实验] 到 '真实' 主机根文件系统路径。
6.7.1.1.59 - 概要 生成 kube-controller-manager 静态 Pod 清单
kubeadm init phase control-plane controller-manager [flags]
选项 --cert-dir string 默认值:"/etc/kubernetes/pki" 存储证书的路径。 --config string kubeadm 配置文件的路径。 --controller-manager-extra-args mapStringString 一组 <flagname>=< 形式的额外参数,传递给控制器管理器(Controller Manager)
或者覆盖其默认配置值 包含名为 "target[suffix][+patchtype].extension" 的文件的目录。
例如,"kube-apiserver0+merge.yaml" 或者 "etcd.json"。
"patchtype" 可以是 "strategic"、"merge" 或 "json" 之一,分别与 kubectl
所支持的 patch 格式相匹配。默认的 "patchtype" 是 "strategic"。
"extension" 必须是 "json" 或 "yaml"。
"suffix" 是一个可选的字符串,用来确定按字母顺序排序时首先应用哪些 patch。 -h, --help controller-manager 操作的帮助命令 --image-repository string 默认值:"k8s.gcr.io" 选择要从中拉取控制平面镜像的容器仓库 --kubernetes-version string 默认值:"stable-1" 为控制平面选择特定的 Kubernetes 版本。 --pod-network-cidr string 指定 Pod 网络的 IP 地址范围。如果设置,控制平面将自动为每个节点分配 CIDR。
从父命令继承的选项 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
6.7.1.1.60 - 概要 生成 kube-scheduler 静态 Pod 清单
kubeadm init phase control-plane scheduler [flags]
选项 --cert-dir string 默认值:"/etc/kubernetes/pki" 存储证书的路径。 --config string kubeadm 配置文件的路径。 --experimental-patches string 包含名为 "target[suffix][+patchtype].extension" 的文件的目录。
例如,"kube-apiserver0+merge.yaml" 或者 "etcd.json"。
"patchtype" 可以是 "strategic"、"merge" 或 "json" 之一,分别与 kubectl
所支持的 patch 格式相匹配。默认的 "patchtype" 是 "strategic"。
"extension" 必须是 "json" 或 "yaml"。
"suffix" 是一个可选的字符串,用来确定按字母顺序排序时首先应用哪些 patch。 -h, --help scheduler 操作的帮助命令 --image-repository string 默认值:"k8s.gcr.io" 选择要从中拉取控制平面镜像的容器仓库 --kubernetes-version string 默认值:"stable-1" 为控制平面选择特定的 Kubernetes 版本。 --scheduler-extra-args mapStringString 一组 <flagname>=<value> 形式的额外参数,用来传递给调度器
或者覆盖其默认参数配置
继承于父命令的选项 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
6.7.1.1.61 - 概要 此命令并非设计用来单独运行。请参阅可用子命令列表。
kubeadm init phase etcd [flags]
选项 继承于父命令的选项 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
6.7.1.1.62 - 概要 为本地单节点 etcd 实例生成静态 Pod 清单文件
kubeadm init phase etcd local [flags]
示例 # 为 etcd 生成静态 Pod 清单文件,其功能等效于 kubeadm init 生成的文件。
kubeadm init phase etcd local
# 使用从配置文件读取的选项为 etcd 生成静态 Pod 清单文件。
kubeadm init phase etcd local --config config.yaml
选项 --cert-dir string 默认值:"/etc/kubernetes/pki" 存储证书的路径。 --config string kubeadm 配置文件的路径。 --experimental-patches string 包含名为 "target[suffix][+patchtype].extension" 的文件的目录的路径。
例如,"kube-apiserver0+merge.yaml" 或仅仅是 "etcd.json"。
"patchtype" 可以是 "strategic"、"merge" 或 "json" 之一,并且它们与 kubectl 支持的补丁格式匹配。
默认的 "patchtype" 为 "strategic"。 "extension" 必须为 "json" 或 "yaml"。
"suffix" 是一个可选字符串,可用于确定首先按字母顺序应用哪些补丁。 -h, --help local 操作的帮助命令 --image-repository string 默认值:"k8s.gcr.io" 选择要从中拉取控制平面镜像的容器仓库
继承于父命令的选项 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
6.7.1.1.63 - 概要 此命令并非设计用来单独运行。请阅读可用子命令列表。
kubeadm init phase kubeconfig [flags]
选项 -h, --help kubeconfig 操作的帮助命令
从父命令继承的选项 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
6.7.1.1.64 - 概要 为管理员和 kubeadm 本身生成 kubeconfig 文件,并将其保存到 admin.conf 文件中。
kubeadm init phase kubeconfig admin [flags]
选项 --apiserver-advertise-address string API 服务器所公布的其正在监听的 IP 地址。如果未设置,则使用默认的网络接口。 --apiserver-bind-port int32 默认值:6443 要绑定到 API 服务器的端口。 --cert-dir string 默认值:"/etc/kubernetes/pki" 保存和存储证书的路径。 --config string kubeadm 配置文件的路径。 --control-plane-endpoint string 为控制平面指定一个稳定的 IP 地址或 DNS 名称。 -h, --help admin 操作的帮助命令 --kubeconfig-dir string 默认值:"/etc/kubernetes" kubeconfig 文件的保存路径。 --kubernetes-version string 默认值:"stable-1" 为控制平面指定特定的 Kubernetes 版本。
继承于父命令的选项 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
6.7.1.1.65 - 概要 生成所有 kubeconfig 文件
kubeadm init phase kubeconfig all [flags]
选项 --apiserver-advertise-address string API 服务器所公布的其正在监听的 IP 地址。如果没有设置,将使用默认的网络接口。 --apiserver-bind-port int32 默认值:6443 要绑定到 API 服务器的端口。 --cert-dir string 默认值:"/etc/kubernetes/pki" 保存和存储证书的路径。 --config string kubeadm 配置文件的路径。 --control-plane-endpoint string 为控制平面指定一个稳定的 IP 地址或 DNS 名称。 -h, --help all 操作的帮助命令 --kubeconfig-dir string 默认值:"/etc/kubernetes" kubeconfig 文件的保存路径。 --kubernetes-version string 默认值:"stable-1" 为控制平面指定特定的 Kubernetes 版本。 --node-name string 指定节点名称。
继承于父命令的选项 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
6.7.1.1.66 - 概要 生成控制器管理器要使用的 kubeconfig 文件,并保存到 controller-manager.conf 文件中。
kubeadm init phase kubeconfig controller-manager [flags]
选项 --apiserver-advertise-address string API 服务器所公布的其正在监听的 IP 地址。如果未设置,则使用默认的网络接口。 --apiserver-bind-port int32 默认值:6443 要绑定到 API 服务器的端口。 --cert-dir string 默认值:"/etc/kubernetes/pki" 保存和存储证书的路径。 --config string kubeadm 配置文件的路径。 --control-plane-endpoint string 为控制平面指定一个稳定的 IP 地址或 DNS 名称。 -h, --help controller-manager 操作的帮助命令 --kubeconfig-dir string 默认值:"/etc/kubernetes" kubeconfig 文件的保存路径。 --kubernetes-version string 默认值:"stable-1" 为控制平面指定特定的 Kubernetes 版本。
继承于父命令的选项 --rootfs 字符串 [实验] 到 '真实' 主机根文件系统的路径。
6.7.1.1.67 - 概要 生成 kubelet 要使用的 kubeconfig 文件,并将其保存到 kubelet.conf 文件。
请注意,该操作目的是仅 应用于引导集群。在控制平面启动之后,应该从 CSR API 请求所有 kubelet 凭据。
kubeadm init phase kubeconfig kubelet [flags]
选项 --apiserver-advertise-address string API 服务器所公布的其正在监听的 IP 地址。如果未设置,则使用默认的网络接口。 --apiserver-bind-port int32 默认值:6443 要绑定到 API 服务器的端口。 --cert-dir string 默认值:"/etc/kubernetes/pki" 保存和存储证书的路径。 --config string kubeadm 配置文件的路径。 --control-plane-endpoint string 为控制平面指定一个稳定的 IP 地址或 DNS 名称。 -h, --help kubelet 操作的帮助命令 --kubeconfig-dir string 默认值:"/etc/kubernetes" kubeconfig 文件的保存路径。 --kubernetes-version string 默认值:"stable-1" 为控制平面选择特定的 Kubernetes 版本。 --node-name string 指定节点的名称。
继承于父命令的选项 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
6.7.1.1.68 - 概要 生成调度器(scheduler)要使用的 kubeconfig 文件,并保存到 scheduler.conf 文件中。
kubeadm init phase kubeconfig scheduler [flags]
选项 --apiserver-advertise-address string API 服务器所公布的其正在监听的 IP 地址。如果未设置,则使用默认的网络接口。 --apiserver-bind-port int32 默认值:6443 要绑定到 API 服务器的端口。 --cert-dir string 默认值:"/etc/kubernetes/pki" 保存和存储证书的路径。 --config string kubeadm 配置文件的路径。 --control-plane-endpoint string 为控制平面指定一个稳定的 IP 地址或 DNS 名称。 -h, --help scheduler 操作的帮助命令 --kubeconfig-dir string 默认值:"/etc/kubernetes" kubeconfig 文件的保存路径。 --kubernetes-version string 默认值:"stable-1" 为控制平面指定特定的 Kubernetes 版本。
继承于父命令的选项 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
6.7.1.1.69 - TLS 引导后更新与 kubelet 相关的设置
kubeadm init phase kubelet-finalize [flags]
示例 # 在 TLS 引导后更新与 kubelet 相关的设置
kubeadm init phase kubelet-finalize all --config
选项 -h, --help kubelet-finalize 操作的帮助命令
继承于父命令的选项 --rootfs string [实验] 到'真实'主机根文件系统的路径。
6.7.1.1.70 - 运行所有 kubelet-finalize 阶段
kubeadm init phase kubelet-finalize all [flags]
示例 # 在 TLS 引导后更新与 kubelet 相关的设置
kubeadm init phase kubelet-finalize all --config
选项 --cert-dir string 默认值: "/etc/kubernetes/pki" 保存和存储证书的路径。 --config string kubeadm 配置文件的路径。 -h, --help all 操作的帮助命令
继承于父命令的选项 --rootfs string [实验] 到'真实'主机根文件系统的路径。
6.7.1.1.71 - 启用 kubelet 客户端证书轮换
kubeadm init phase kubelet-finalize experimental-cert-rotation [flags]
选项 --cert-dir string Default: "/etc/kubernetes/pki" 保存和存储证书的路径。 --config string kubeadm 配置文件的路径。 -h, --help experimental-cert-rotation 操作的帮助命令
继承于父命令的选项 --rootfs string [实验] 到'真实'主机根文件系统的路径。
6.7.1.1.72 - 概要 使用 kubelet 配置文件编写一个文件,并使用特定节点的 kubelet 设置编写一个环境文件,然后(重新)启动 kubelet。
kubeadm init phase kubelet-start [flags]
示例 # 从 InitConfiguration 文件中写入带有 kubelet 参数的动态环境文件。
kubeadm init phase kubelet-start --config config.yaml
选项 --config string kubeadm 配置文件的路径。 --cri-socket string 连接到 CRI 套接字的路径。如果为空,则 kubeadm 将尝试自动检测该值;仅当安装了多个 CRI 或具有非标准 CRI 套接字时,才使用此选项。 -h, --help kubelet-start 操作的帮助命令 --node-name string 指定节点名称。
从父命令继承的选项 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
6.7.1.1.73 - 概要 标记 Node 节点为控制平面节点
kubeadm init phase mark-control-plane [flags]
示例 # 将控制平面标签和污点应用于当前节点,其功能等效于 kubeadm init执行的操作。
kubeadm init phase mark-control-plane --config config.yml
# 将控制平面标签和污点应用于特定节点
kubeadm init phase mark-control-plane --node-name myNode
选项 --config string kubeadm 配置文件的路径。 -h, --help mark-control-plane 操作的帮助命令 --node-name string 指定节点名称。
从父命令继承的选项 --rootfs 字符串 [实验] 到 '真实' 主机根文件系统的路径。
6.7.1.1.74 - 概要 运行 kubeadm init 前的启动检查。
kubeadm init phase preflight [flags]
案例 # 使用配置文件对 kubeadm init 进行启动检查。
kubeadm init phase preflight --config kubeadm-config.yml
选项 --config string kubeadm 配置文件的路径。 -h, --help preflight 操作的帮助命令 --ignore-preflight-errors stringSlice 错误将显示为警告的检查列表:例如:'IsPrivilegedUser,Swap'。取值为 'all' 时将忽略检查中的所有错误。
继承于父命令的选项 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
6.7.1.1.75 - 概要 此命令并非设计用来单独运行。请参阅可用子命令列表。
kubeadm init phase upload-certs [flags]
选项 --certificate-key string 用于加密 kubeadm-certs Secret 中的控制平面证书的密钥。 --config string kubeadm 配置文件的路径。 -h, --help upload-certs 操作的帮助命令 --kubeconfig string 默认值:"/etc/kubernetes/admin.conf" 用来与集群通信的 kubeconfig 文件。
如果此标志未设置,则可以在一组标准的位置搜索现有的 kubeconfig 文件。 --skip-certificate-key-print 不要打印输出用于加密控制平面证书的密钥。 --upload-certs 将控制平面证书上传到 kubeadm-certs Secret。
从父命令继承的选项 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
6.7.1.1.76 - 概要 此命令并非设计用来单独运行。请参阅可用的子命令列表。
kubeadm init phase upload-config [flags]
选项 -h, --help upload-config 操作的帮助命令
从父命令中继承的选项 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
6.7.1.1.77 - 概要 将所有配置上传到 ConfigMap
kubeadm init phase upload-config all [flags]
选项 --config string kubeadm 配置文件的路径。 -h, --help all 操作的帮助命令 --kubeconfig string 默认值:"/etc/kubernetes/admin.conf" 与集群通信时使用的 kubeconfig 文件。如果未设置该参数,则可以在一组标准位置中搜索现有的 kubeconfig 文件。
从父命令继承的选项 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
6.7.1.1.78 - 概要 将 kubeadm ClusterConfiguration 上传到 kube-system 命名空间中名为 kubeadm-config 的 ConfigMap 中。
这样就可以正确配置系统组件,并在升级时提供无缝的用户体验。
另外,可以使用 kubeadm 配置。
kubeadm init phase upload-config kubeadm [flags]
示例 # 上传集群配置
kubeadm init phase upload-config --config=myConfig.yaml
选项 --config string kubeadm 配置文件的路径。 -h, --help kubeadm 操作的帮助命令 --kubeconfig string 默认值:"/etc/kubernetes/admin.conf" 与集群通信时使用的 kubeconfig 文件。如果未设置该参数,则可以在一组标准位置中搜索现有的 kubeconfig 文件。
从父命令继承的选项 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
6.7.1.1.79 - 概要 将从 kubeadm InitConfiguration 对象提取的 kubelet 配置上传到集群中 kubelet-config-1.X 形式的
ConfigMap,其中 X 是当前(API 服务器)Kubernetes 版本的次要版本。
kubeadm init phase upload-config kubelet [flags]
示例 # 将 kubelet 配置从 kubeadm 配置文件上传到集群中的 ConfigMap。
kubeadm init phase upload-config kubelet --config kubeadm.yaml
选项 --config string 到 kubeadm 配置文件的路径。 -h, --help kubelet 操作的帮助命令 --kubeconfig string 默认值:"/etc/kubernetes/admin.conf" 与集群通信时使用的 kubeconfig 文件。如果未设置该标签,则可以通过一组标准路径来寻找已有的 kubeconfig 文件。
从父命令继承的选项 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
6.7.1.1.80 - 摘要 当节点加入 kubeadm 初始化的集群时,我们需要建立双向信任。
这个过程可以分解为发现(让待加入节点信任 Kubernetes 控制平面节点)和 TLS 引导(让Kubernetes 控制平面节点信任待加入节点)两个部分。
有两种主要的发现方案。
第一种方法是使用共享令牌和 API 服务器的 IP 地址。
第二种是提供一个文件 - 标准 kubeconfig 文件的一个子集。
该文件可以是本地文件,也可以通过 HTTPS URL 下载。
格式是 kubeadm join --discovery-token abcdef.1234567890abcdef 1.2.3.4:6443、kubeadm join--discovery-file path/to/file.conf 或者kubeadm join --discovery-file https://url/file.conf。
只能使用其中一种。
如果发现信息是从 URL 加载的,必须使用 HTTPS。
此外,在这种情况下,主机安装的 CA 包用于验证连接。
如果使用共享令牌进行发现,还应该传递 --discovery-token-ca-cert-hash 参数来验证 Kubernetes 控制平面节点提供的根证书颁发机构(CA)的公钥。
此参数的值指定为 "<hash-type>:<hex-encoded-value>",其中支持的哈希类型为 "sha256"。哈希是通过 Subject Public Key Info(SPKI)对象的字节计算的(如 RFC7469)。
这个值可以从 "kubeadm init" 的输出中获得,或者可以使用标准工具进行计算。
可以多次重复 --discovery-token-ca-cert-hash 参数以允许多个公钥。
如果无法提前知道 CA 公钥哈希,则可以通过 --discovery-token-unsafe-skip-ca-verification 参数禁用此验证。
这削弱了kubeadm 安全模型,因为其他节点可能会模仿 Kubernetes 控制平面节点。
TLS 引导机制也通过共享令牌驱动。
这用于向 Kubernetes 控制平面节点进行临时的身份验证,以提交本地创建的密钥对的证书签名请求(CSR)。
默认情况下,kubeadm 将设置 Kubernetes 控制平面节点自动批准这些签名请求。
这个令牌通过 --tls-bootstrap-token abcdef.1234567890abcdef 参数传入。
通常两个部分会使用相同的令牌。
在这种情况下可以使用 --token 参数,而不是单独指定每个令牌。
"join [api-server-endpoint]" 命令执行下列阶段:
preflight Run join pre-flight checks
control-plane-prepare Prepare the machine for serving a control plane
/download-certs [EXPERIMENTAL] Download certificates shared among control-plane nodes from the kubeadm-certs Secret
/certs Generate the certificates for the new control plane components
/kubeconfig Generate the kubeconfig for the new control plane components
/control-plane Generate the manifests for the new control plane components
kubelet-start Write kubelet settings, certificates and (re)start the kubelet
control-plane-join Join a machine as a control plane instance
/etcd Add a new local etcd member
/update-status Register the new control-plane node into the ClusterStatus maintained in the kubeadm-config ConfigMap
/mark-control-plane Mark a node as a control-plane
kubeadm join [api-server-endpoint] [flags]
选项 --apiserver-advertise-address string 如果该节点托管一个新的控制平面实例,则 API 服务器将公布其正在侦听的 IP 地址。如果未设置,则使用默认网络接口。 --apiserver-bind-port int32 默认值: 6443 如果节点应该托管新的控制平面实例,则为 API 服务器要绑定的端口。 --certificate-key string 使用此密钥可以解密由 init 上传的证书 secret。 --config string kubeadm 配置文件的路径。 --control-plane 在此节点上创建一个新的控制平面实例 --cri-socket string 要连接的 CRI 套接字的路径。如果为空,则 kubeadm 将尝试自动检测此值;仅当安装了多个 CRI 或具有非标准 CRI 插槽时,才使用此选项。 --discovery-file string 对于基于文件的发现,给出用于加载集群信息的文件或者 URL。 --discovery-token string 对于基于令牌的发现,该令牌用于验证从 API 服务器获取的集群信息。 --discovery-token-ca-cert-hash stringSlice 对基于令牌的发现,验证根 CA 公钥是否与此哈希匹配 (格式: "<type>:<value>")。 --discovery-token-unsafe-skip-ca-verification 对于基于令牌的发现,允许在未关联 --discovery-token-ca-cert-hash 参数的情况下添加节点。 --experimental-patches string 包含名为 "target[suffix][+patchtype].extension" 的文件的目录的路径。
例如,"kube-apiserver0+merge.yaml" 或仅仅是 "etcd.json"。
"patchtype" 可以是 "strategic"、"merge" 或 "json" 之一,并且它们与 kubectl 支持的补丁格式匹配。
默认的 "patchtype" 为 "strategic"。 "extension" 必须为 "json" 或 "yaml"。
"suffix" 是一个可选字符串,可用于确定首先按字母顺序应用哪些补丁。 -h, --help join 操作的帮助命令 --ignore-preflight-errors stringSlice 错误将显示为警告的检查列表;例如:'IsPrivilegedUser,Swap'。取值为 'all' 时将忽略检查中的所有错误。 --node-name string 指定节点的名称 --skip-phases stringSlice 要跳过的阶段列表 --tls-bootstrap-token string 指定在加入节点时用于临时通过 Kubernetes 控制平面进行身份验证的令牌。 --token string 如果未提供这些值,则将它们用于 discovery-token 令牌和 tls-bootstrap 令牌。
从父命令继承的选项 --rootfs string [实验] 指向 '真实' 宿主机根文件系统的路径。
6.7.1.1.81 - 概要 使用此命令来调用 join 工作流程的某个阶段
选项 从父命令中继承的选项 --rootfs string [实验] 指向 '真实' 宿主机根文件系统的路径。
6.7.1.1.82 - 概要 添加作为控制平面实例的机器
kubeadm join phase control-plane-join [flags]
示例 # 将机器作为控制平面实例加入
kubeadm join phase control-plane-join all
选项 -h, --help control-plane-join 操作的帮助命令
从父命令中继承的选项 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
6.7.1.1.83 - 概要 添加作为控制平面实例的机器
kubeadm join phase control-plane-join all [flags]
选项 --apiserver-advertise-address string 如果该节点托管一个新的控制平面实例,则 API 服务器将公布其正在侦听的 IP 地址。如果未设置,则使用默认网络接口。 --config string kubeadm 配置文件的路径。 --experimental-control-plane 在此节点上创建一个新的控制平面实例 -h, --help all 操作的帮助命令 --node-name string 指定节点名称。
从父命令继承的选项 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
6.7.1.1.84 - 概要 添加新的本地 etcd 成员
kubeadm join phase control-plane-join etcd [flags]
选项 --apiserver-advertise-address string 如果该节点托管一个新的控制平面实例,则 API 服务器将公布其正在侦听的 IP 地址。如果未设置,则使用默认网络接口。 --config string kubeadm 配置文件的路径。 --control-plane 在此节点上创建一个新的控制平面实例 --experimental-patches string 包含名为 "target[suffix][+patchtype].extension" 的文件的目录的路径。
例如,"kube-apiserver0+merge.yaml" 或仅仅是 "etcd.json"。
"patchtype" 可以是"strategic"、"merge" 或 "json" 之一,并且它们与 kubectl 支持的补丁格式匹配。
默认的 "patchtype" 为 "strategic"。 "extension" 必须为 "json" 或 "yaml"。
"suffix" 是一个可选字符串,可用于确定首先按字母顺序应用哪些补丁。 -h, --help etcd 操作的帮助命令 --node-name string 指定节点的名称
从父命令中继承的选项 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
6.7.1.1.85 - 概要 将 Node 节点标记为控制平面节点
kubeadm join phase control-plane-join mark-control-plane [flags]
选项 --config string kubeadm 配置文件的路径。 --control-plane 在此节点上创建一个新的控制平面实例 -h, --help mark-control-plane 操作的帮助命令 --node-name string 指定节点的名称
从父命令中继承的选项 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
6.7.1.1.86 - 概要 将新的控制平面节点注册到 kubeadm-config ConfigMap 维护的 ClusterStatus 中
kubeadm join phase control-plane-join update-status [flags]
选项 --apiserver-advertise-address string 如果该节点托管一个新的控制平面实例,则 API 服务器将公布其正在侦听的 IP 地址。如果未设置,则使用默认网络接口。 --config string kubeadm 配置文件的路径。 --control-plane 在此节点上创建一个新的控制平面实例 -h, --help update-status 操作的帮助命令 --node-name string 指定节点名称。
从父命令中继承的选项 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
6.7.1.1.87 - 概要 准备为控制平面服务的机器
kubeadm join phase control-plane-prepare [flags]
示例 # 准备为控制平面服务的机器
kubeadm join phase control-plane-prepare all
选项 -h, --help control-plane-prepare 操作的帮助命令
从父命令中继承的选项 --rootfs string [实验] 指向 '真实' 宿主机根文件系统的路径。
6.7.1.1.88 - 概要 准备为控制平面服务的机器
kubeadm join phase control-plane-prepare all [api-server-endpoint] [flags]
选项 --apiserver-advertise-address string 如果该节点托管一个新的控制平面实例,则 API 服务器将公布其正在侦听的 IP 地址。如果未设置,则使用默认网络接口。 --apiserver-bind-port int32 默认值:6443 如果该节点托管一个新的控制平面实例,则为 API 服务器要绑定的端口。 --certificate-key string 使用此密钥解密由 init 上传的证书 secrets。 --config string kubeadm 配置文件的路径。 --control-plane 在此节点上创建一个新的控制平面实例 --discovery-file string 对于基于文件的发现,给出用于加载集群信息的文件或者 URL。 --discovery-token string 对于基于令牌的发现,该令牌用于验证从 API 服务器获取的集群信息。 --discovery-token-ca-cert-hash stringSlice 对于基于令牌的发现,请验证根 CA 公钥是否匹配此哈希值(格式:"<type>:<value>")。 --discovery-token-unsafe-skip-ca-verification 对于基于令牌的发现,允许在未关联 --discovery-token-ca-cert-hash 参数的情况下添加节点。 --experimental-patches string 包含名为 "target[suffix][+patchtype].extension" 的文件的目录的路径。
例如,"kube-apiserver0+merge.yaml" 或仅仅是 "etcd.json"。
"patchtype" 可以是 "strategic"、"merge" 或 "json" 之一,并且它们与 kubectl 支持的补丁格式匹配。
默认的 "patchtype" 为 "strategic"。 "extension" 必须为 "json" 或 "yaml"。
"suffix" 是一个可选字符串,可用于确定首先按字母顺序应用哪些补丁。 -h, --help all 操作的帮助命令 --node-name string 指定节点名称。 --tls-bootstrap-token string 指定在加入节点时用于临时通过 Kubernetes 控制平面进行身份验证的令牌。 --token string 如果未提供这些值,则将它们用于 discovery-token 令牌和 tls-bootstrap 令牌。
从父命令继承的选项 --rootfs string [实验] 指向 '真实' 宿主机根文件系统的路径。
6.7.1.1.89 - 概要 为新的控制平面组件生成证书
kubeadm join phase control-plane-prepare certs [api-server-endpoint] [flags]
选项 --apiserver-advertise-address string 如果该节点托管一个新的控制平面实例,则 API 服务器将公布其正在侦听的 IP 地址。如果未设置,则使用默认网络接口。 --config string kubeadm 配置文件的路径。 --control-plane 在此节点上创建一个新的控制平面实例 --discovery-file string 对于基于文件的发现,给出用于加载集群信息的文件或者 URL。 --discovery-token string 对于基于令牌的发现,该令牌用于验证从 API 服务器获取的集群信息。 --discovery-token-ca-cert-hash stringSlice 对于基于令牌的发现,请验证根 CA 公钥是否匹配此哈希值(格式:"<type>:<value>")。 --discovery-token-unsafe-skip-ca-verification 对于基于令牌的发现,允许在未关联 --discovery-token-ca-cert-hash 参数的情况下添加节点。 -h, --help certs 操作的帮助命令 --node-name string 指定节点名称。 --tls-bootstrap-token string 指定在加入节点时用于临时通过 Kubernetes 控制平面进行身份验证的令牌。 --token string 如果未提供这些值,则将它们用于 discovery-token 令牌和 tls-bootstrap 令牌。
从父命令继承的选项 --rootfs string [实验] 指向 '真实' 宿主机根文件系统的路径。
6.7.1.1.90 - 概要 为新的控制平面组件生成清单(manifest)
kubeadm join phase control-plane-prepare control-plane [flags]
选项 --apiserver-advertise-address string 对于将要托管新的控制平面实例的节点,指定 API 服务器将公布的其正在侦听的 IP 地址。如果未设置,则使用默认网络接口。 --apiserver-bind-port int32 默认值:6443 针对将要托管新的控制平面实例的节点,设置 API 服务器要绑定的端口。 --config string kubeadm 配置文件的路径。 --control-plane 在此节点上创建一个新的控制平面实例 --experimental-patches string 包含名为 "target[suffix][+patchtype].extension" 的文件的目录的路径。
例如,"kube-apiserver0+merge.yaml" 或仅仅是 "etcd.json"。
"patchtype" 可以是 "strategic"、"merge" 或 "json" 之一,并且它们与 kubectl 支持的补丁格式匹配。
默认的 "patchtype" 为 "strategic"。 "extension" 必须为 "json" 或 "yaml"。
"suffix" 是一个可选字符串,可用于确定首先按字母顺序应用哪些补丁。 -h, --help control-plane 操作的帮助命令
从父命令中继承的选项 --rootfs string [实验] 指向 '真实' 宿主机根文件系统的路径。
6.7.1.1.91 - 概要 [实验]从 kubeadm-certs Secret 下载控制平面节点之间共享的证书
kubeadm join phase control-plane-prepare download-certs [api-server-endpoint] [flags]
选项 --certificate-key string 使用此密钥可以解密由 init 上传的证书 secret。 --config string kubeadm 配置文件的路径。 --control-plane 在此节点上创建一个新的控制平面实例 --discovery-file string 对于基于文件的发现,给出用于加载集群信息的文件或者 URL。 --discovery-token string 对于基于令牌的发现,该令牌用于验证从 API 服务器获取的集群信息。 --discovery-token-ca-cert-hash stringSlice 对于基于令牌的发现,请验证根 CA 公钥是否匹配此哈希值(格式:"<type>:<value>")。 --discovery-token-unsafe-skip-ca-verification 对于基于令牌的发现,允许在未关联 --discovery-token-ca-cert-hash 参数的情况下添加节点。 -h, --help kubeconfig 操作的帮助命令 --tls-bootstrap-token string 指定在加入节点时用于临时通过 Kubernetes 控制平面进行身份验证的令牌。 --token string 如果未提供这些值,则将它们用于 discovery-token 令牌和 tls-bootstrap 令牌。
从父命令中继承的选项 --rootfs string [实验] 指向 '真实' 宿主机根文件系统的路径。
6.7.1.1.92 - 概要 为新的控制平面组件生成 kubeconfig
kubeadm join phase control-plane-prepare kubeconfig [api-server-endpoint] [flags]
选项 --certificate-key string 使用此密钥可以解密由 init 上传的证书 secret。 --config string kubeadm 配置文件的路径。 --control-plane 在此节点上创建一个新的控制平面实例 --discovery-file string 对于基于文件的发现,给出用于加载集群信息的文件或者 URL。 --discovery-token string 对于基于令牌的发现,该令牌用于验证从 API 服务器获取的集群信息。 --discovery-token-ca-cert-hash stringSlice 对于基于令牌的发现,请验证根 CA 公钥是否匹配此哈希值(格式:"<type>:<value>")。 --discovery-token-unsafe-skip-ca-verification 对于基于令牌的发现,允许在未关联 --discovery-token-ca-cert-hash 参数的情况下添加节点。 -h, --help kubeconfig 操作的帮助命令 --tls-bootstrap-token string 指定在加入节点时用于临时通过 Kubernetes 控制平面进行身份验证的令牌。 --token string 如果未提供这些值,则将它们用于 discovery-token 令牌和 tls-bootstrap 令牌。
从父命令中继承的选项 --rootfs string [实验] 指向 '真实' 宿主机根文件系统的路径。
6.7.1.1.93 - 概要 生成一个包含 KubeletConfiguration 的文件和一个包含特定于节点的 kubelet 配置的环境文件,然后(重新)启动 kubelet。
kubeadm join phase kubelet-start [api-server-endpoint] [flags]
选项 --config string kubeadm 配置文件的路径。 --cri-socket string 提供给 CRI 套接字建立连接的路径。如果为空,则 kubeadm 将尝试自动检测该值;仅当安装了多个 CRI 或具有非标准 CRI 套接字时,才使用此选项。 --discovery-file string For file-based discovery, a file or URL from which to load cluster information.
对于基于文件的发现,给出用于加载集群信息的文件或者 URL。 --discovery-token string 对于基于令牌的发现,该令牌用于验证从 API 服务器获取的集群信息。 --discovery-token-ca-cert-hash stringSlice 对于基于令牌的发现,验证根 CA 公钥是否匹配此哈希值(格式:"<type>:<value>")。 --discovery-token-unsafe-skip-ca-verification 对于基于令牌的发现,允许在未关联 --discovery-token-ca-cert-hash 参数的情况下添加节点。 -h, --help kubelet-start 操作的帮助命令 --node-name string 指定节点名称。 --tls-bootstrap-token string 指定在加入节点时用于临时通过 Kubernetes 控制平面进行身份验证的令牌。 --token string 如果未提供这些值,则将它们用于 discovery-token 令牌和 tls-bootstrap 令牌。
从父命令继承的选项 --rootfs string [实验] 指向 '真实' 宿主机根文件系统的路径。
6.7.1.1.94 - 概要 运行 kubeadm join 命令添加节点前检查。
kubeadm join phase preflight [api-server-endpoint] [flags]
示例 # 使用配置文件运行 kubeadm join 命令添加节点前检查。
kubeadm join phase preflight --config kubeadm-config.yml
选项 --apiserver-advertise-address string 对于将要托管新的控制平面实例的节点,指定 API 服务器将公布的其正在侦听的 IP 地址。如果未设置,则使用默认网络接口。 --apiserver-bind-port int32 默认值:6443 针对将要托管新的控制平面实例的节点,设置 API 服务器要绑定的端口。 --certificate-key string 使用此密钥可以解密由 `init` 操作上传的证书 secret。 --config string kubeadm 配置文件的路径。 --control-plane 在此节点上创建一个新的控制平面实例 --cri-socket string 提供给 CRI 套接字建立连接的路径。如果为空,则 kubeadm 将尝试自动检测该值;仅当安装了多个 CRI 或具有非标准 CRI 套接字时,才使用此选项。 --discovery-file string 对于基于文件的发现,给出用于加载集群信息的文件或者 URL。 --discovery-token string 对于基于令牌的发现,该令牌用于验证从 API 服务器获取的集群信息。 --discovery-token-ca-cert-hash stringSlice 对于基于令牌的发现,验证根 CA 公钥是否匹配此哈希值(格式:"<type>:<value>")。 --discovery-token-unsafe-skip-ca-verification 对于基于令牌的发现,允许在未关联 --discovery-token-ca-cert-hash 参数的情况下添加节点。 -h, --help preflight 操作的帮助命令 --ignore-preflight-errors stringSlice 错误将显示为警告的检查列表;例如:'IsPrivilegedUser,Swap'。取值为 'all' 时将忽略检查中的所有错误。 --node-name string 指定节点名称。 --tls-bootstrap-token string 指定在加入节点时用于临时通过 Kubernetes 控制平面进行身份验证的令牌。 --token string 如果未提供这些值,则将它们用于 discovery-token 令牌和 tls-bootstrap 令牌。
从父命令继承的选项 --rootfs string [实验] 指向 '真实' 宿主机根文件系统的路径。
6.7.1.1.95 - 概要 尽最大努力还原通过 'kubeadm init' 或者 'kubeadm join' 操作对主机所做的更改
"reset" 命令执行以下阶段:
preflight Run reset pre-flight checks
update-cluster-status Remove this node from the ClusterStatus object.
remove-etcd-member Remove a local etcd member.
cleanup-node Run cleanup node.
kubeadm reset [flags]
选项 --cert-dir string 默认值:"/etc/kubernetes/pki" 存储证书的目录路径。如果已指定,则需要清空此目录。 --cri-socket string 要连接的 CRI 套接字的路径。如果为空,则 kubeadm 将尝试自动检测此值;仅当安装了多个CRI 或具有非标准 CRI 插槽时,才使用此选项。 -f, --force 在不提示确认的情况下重置节点。 -h, --help reset 操作的帮助命令 --ignore-preflight-errors stringSlice 错误将显示为警告的检查列表;例如:'IsPrivilegedUser,Swap'。取值为 'all' 时将忽略检查中的所有错误。 --kubeconfig string 默认值:"/etc/kubernetes/admin.conf" 与集群通信时使用的 kubeconfig 文件。如果未设置该标志,则可以在一组标准位置中搜索现有的 kubeconfig 文件。 --skip-phases stringSlice 要跳过的阶段列表
从父命令继承的选项 --rootfs string [实验] 指向 '真实' 宿主机根文件系统的路径。
6.7.1.1.96 - 概要 使用此命令来调用 reset 工作流程的某个阶段
选项 从父命令继承的选项 --rootfs string [实验] 指向 '真实' 宿主机根文件系统的路径。
6.7.1.1.97 - 概要 执行 cleanup node(清理节点)操作。
kubeadm reset phase cleanup-node [flags]
选项 --cert-dir string 默认值:"/etc/kubernetes/pki" 存储证书的目录路径。如果已指定,则需要清空此目录。 --cri-socket string 要连接的 CRI 套接字的路径。如果为空,则 kubeadm 将尝试自动检测此值;仅当安装了多个CRI 或具有非标准 CRI 插槽时,才使用此选项。 -h, --help cleanup-node 操作的帮助命令
从父命令继承的选项 --rootfs string [实验] 指向 '真实' 宿主机根文件系统的路径。
6.7.1.1.98 - 概要 kubeadm reset(重置)前运行启动前检查。
kubeadm reset phase preflight [flags]
选项 -f, --force 在不提示确认的情况下重置节点。 -h, --help preflight 操作的帮助命令 --ignore-preflight-errors stringSlice 错误将显示为警告的检查列表;例如:'IsPrivilegedUser,Swap'。取值为 'all' 时将忽略检查中的所有错误。
从父命令继承的选项 --rootfs string [实验] 指向 '真实' 宿主机根文件系统的路径。
6.7.1.1.99 - 概要 上传关于当前状态的配置,以便 'kubeadm upgrade' 以后可以知道如何配置升级后的集群。
kubeadm config upload [flags]
选项 从父命令继承的选项 --kubeconfig string 默认值: "/etc/kubernetes/admin.conf" 用于和集群通信的 KubeConfig 文件。如果它没有被设置,那么 kubeadm 将会搜索一个已经存在于标准路径的 KubeConfig 文件。 --rootfs string [实验] 到'真实'主机根文件系统的路径。
6.7.1.1.100 - 概要 如果该节点是控制平面节点,从 ClusterStatus 对象中删除该节点。
kubeadm reset phase update-cluster-status [flags]
选项 -h, --help update-cluster-status 操作的帮助命令
从父命令继承的选项 --rootfs string [实验] 指向 '真实' 宿主机根文件系统的路径。
6.7.1.1.101 - 概要 此命令管理引导令牌(bootstrap token)。它是可选的,仅适用于高级用例。
简而言之,引导令牌(bootstrap token)用于在客户端和服务器之间建立双向信任。
当客户端(例如,即将加入集群的节点)需要时,可以使用引导令牌相信正在与之通信的服务器。
然后可以使用具有 “签名” 的引导令牌。
引导令牌还可以作为一种允许对 API 服务器进行短期身份验证的方法(令牌用作 API 服务器信任客户端的方式),例如用于执行 TLS 引导程序。
引导令牌准确来说是什么?
它是位于 kube-system 命名空间中类型为 “bootstrap.kubernetes.io/token” 的一个 Secret。 引导令牌的格式必须为 “[a-z0-9]{6}.[a-z0-9]{16}”,前一部分是公共令牌 ID,而后者是令牌秘钥,必须在任何情况下都保密! 必须将 Secret 的名称命名为 “bootstrap-token-(token-id)”。 您可以在此处阅读有关引导令牌(bootstrap token)的更多信息:
/docs/admin/bootstrap-tokens/
kubeadm token [flags]
选项 --dry-run 是否启用 `dry-run` 模式 -h, --help token 操作的帮助命令 --kubeconfig string 默认值:"/etc/kubernetes/admin.conf" 与集群通信时使用的 kubeconfig 文件。如果未设置,则搜索一组标准位置以查找现有 kubeconfig 文件。
从父命令继承的选项 --rootfs string [实验] 指向 '真实' 宿主机根文件系统的路径。
6.7.1.1.102 - 概要 这个命令将为你创建一个引导令牌。
您可以设置此令牌的用途,"有效时间" 和可选的人性化的描述。
这里的 [token] 是指将要生成的实际令牌。
该令牌应该是一个通过安全机制生成的随机令牌,形式为 "[a-z0-9]{6}.[a-z0-9]{16}"。
如果没有给出 [token],kubeadm 将生成一个随机令牌。
kubeadm token create [token]
选项 --config string kubeadm 配置文件的路径。 --description string 针对令牌用途的人性化的描述。 --groups stringSlice 默认值:[system:bootstrappers:kubeadm:default-node-token] 此令牌用于身份验证时将进行身份验证的其他组。必须匹配 "\\Asystem:bootstrappers:[a-z0-9:-]{0,255}[a-z0-9]\\z" -h, --help create 操作的帮助命令 --print-join-command 不仅仅打印令牌,而是打印使用令牌加入集群所需的完整 'kubeadm join' 参数。 --ttl duration 默认值:24h0m0s 令牌有效时间,超过该时间令牌被自动删除。(例如: 1s, 2m, 3h)。如果设置为 '0',令牌将永远不过期。 --usages stringSlice 默认值:[signing,authentication] 描述可以使用此令牌的方式。你可以多次使用 `--usages` 或者提供一个以逗号分隔的选项列表。合法选项有: [signing,authentication]
从父命令继承的选项 --dry-run 是否启用 `dry-run` 运行模式 --kubeconfig string 默认值:"/etc/kubernetes/admin.conf" 用于和集群通信的 KubeConfig 文件。如果它没有被设置,那么 kubeadm 将会搜索一个已经存在于标准路径的 KubeConfig 文件。 --rootfs string [实验] 指向 '真实' 宿主机根文件系统的路径。
6.7.1.1.103 - 概要 这个命令将为你删除指定的引导令牌列表。
[token-value] 是要删除的 "[a-z0-9]{6}.[a-z0-9]{16}" 形式的完整令牌或者是 "[a-z0-9]{6}" 形式的的令牌 ID。
kubeadm token delete [token-value] ...
选项 从父命令继承的选项 --dry-run 是否启用 `dry-run` 运行模式 --kubeconfig string 默认值:"/etc/kubernetes/admin.conf" 用于和集群通信的 KubeConfig 文件。如果它没有被设置,那么 kubeadm 将会搜索一个已经存在于标准路径的 KubeConfig 文件。 --rootfs string [实验] 指向 '真实' 宿主机根文件系统的路径。
6.7.1.1.104 - 概要 此命令将打印一个随机生成的可以被 "init" 和 "join" 命令使用的引导令牌。
您不必使用此命令来生成令牌。你可以自己设定,只要格式符合 "[a-z0-9]{6}.[a-z0-9]{16}"。这个命令提供是为了方便生成规定格式的令牌。
您也可以使用 "kubeadm init" 并且不指定令牌,该命令会生成一个令牌并打印出来。
kubeadm token generate [flags]
选项 -h, --help generate 操作的帮助命令
从父命令继承的选项 --dry-run 是否启用 `dry-run` 运行模式 --kubeconfig string 默认值:"/etc/kubernetes/admin.conf" 用于和集群通信的 KubeConfig 文件。如果它没有被设置,那么 kubeadm 将会搜索一个已经存在于标准路径的 KubeConfig 文件。 --rootfs string [实验] 指向 '真实' 宿主机根文件系统的路径。
6.7.1.1.105 - 概要 此命令将为您列出所有的引导令牌。
kubeadm token list [flags]
选项 --allow-missing-template-keys 默认值:true 如果设置为 true,则在模板中缺少字段或哈希表的键时忽略模板中的任何错误。
仅适用于 golang 和 jsonpath 输出格式。 -o, --experimental-output string 默认值:"text" 输出格式:text|json|yaml|go-template|go-template-file|template|templatefile|jsonpath|jsonpath-as-json|jsonpath-file 其中之一 -h, --help list 操作的帮助命令
从父命令继承的选项 --dry-run 是否启用 `dry-run` 模式 --kubeconfig string 默认值:"/etc/kubernetes/admin.conf" 用于和集群通信的 kubeconfig 文件。如果它没有被设置,那么 kubeadm 将会搜索一个已经存在于标准路径的 kubeconfig 文件。 --rootfs string [实验] 指向 '真实' 宿主机根文件系统的路径。
6.7.1.1.106 - 概要 此命令能将集群平滑升级到新版本
kubeadm upgrade [flags]
选项 -h, --help upgrade 操作的帮助命令
继承于父命令的选项 --rootfs string [实验] 指向 '真实' 宿主机根文件系统的路径。
6.7.1.1.107 - 概要 将 Kubernetes 集群升级到指定版本
kubeadm upgrade apply [version]
选项 --allow-experimental-upgrades 显示 Kubernetes 的不稳定版本作为升级替代方案,并允许升级到 Kubernetes 的 alpha/beta 或 RC 版本。 --allow-release-candidate-upgrades 显示 Kubernetes 的候选版本作为升级替代方案,并允许升级到 Kubernetes 的 RC 版本。 --certificate-renewal Default: true 执行升级期间更改的组件所使用的证书的更新。 --config string kubeadm 配置文件的路径。 --dry-run 不要更改任何状态,只输出要执行的操作。 --etcd-upgrade 默认值: true 执行 etcd 的升级。 --experimental-patches string 包含名为 "target[suffix][+patchtype].extension" 的文件的目录的路径。
例如,"kube-apiserver0+merge.yaml" 或仅仅是 "etcd.json"。
"patchtype" 可以是 "strategic"、"merge" 或 "json" 之一,并且它们与 kubectl 支持的补丁格式匹配。
默认的 "patchtype" 为 "strategic"。 "extension" 必须为 "json" 或 "yaml"。
"suffix" 是一个可选字符串,可用于确定首先按字母顺序应用哪些补丁。 --feature-gates string 一组键值对,用于描述各种功能。选项包括: IPv6DualStack=true|false (ALPHA - 默认=false) PublicKeysECDSA=true|false (ALPHA - 默认=false) -f, --force 强制升级,但可能无法满足某些要求。这也意味着非交互模式。 -h, --help apply 操作的帮助命令 --ignore-preflight-errors stringSlice 错误将显示为警告的检查列表;例如:'IsPrivilegedUser,Swap'。取值为 'all' 时将忽略检查中的所有错误。 --kubeconfig string 默认值:"/etc/kubernetes/admin.conf" 与集群通信时使用的 kubeconfig 文件。如果未设置标志,则在相关目录下搜索以查找现有 kubeconfig 文件。 --print-config 指定是否应打印将在升级中使用的配置文件。 -y, --yes 执行升级,不提示确认(非交互模式)。
从父命令继承的选项 --rootfs string [实验] 指向 '真实' 宿主机根文件系统的路径。
6.7.1.1.108 - 概述 显示哪些差异将被应用于现有的静态 pod 资源清单。参考: kubeadm upgrade apply --dry-run
kubeadm upgrade diff [version] [flags]
选项 --api-server-manifest string 默认值:"/etc/kubernetes/manifests/kube-apiserver.yaml" API服务器清单的路径 --config string kubeadm 配置文件的路径 -c, --context-lines int 默认值:3 差异中有多少行上下文 --controller-manager-manifest string 默认值: "/etc/kubernetes/manifests/kube-controller-manager.yaml" 控制器清单的路径 -h, --help 帮助 --kubeconfig string 默认值:"/etc/kubernetes/admin.conf" 与集群通信时使用的 kubeconfig 文件,如果标志是未设置,则可以在一组标准位置中搜索现有的 kubeconfig 文件。 --scheduler-manifest string 默认值:"/etc/kubernetes/manifests/kube-scheduler.yaml" 调度程序清单的路径
从父命令继承的选项 --rootfs string [EXPERIMENTAL] “真实”主机根文件系统的路径。
6.7.1.1.109 - 概要 升级集群中某个节点的命令
"node" 命令执行以下阶段:
preflight 执行节点升级前检查
control-plane 如果存在的话,升级部署在该节点上的管理面实例
kubelet-config 更新该节点上的 kubelet 配置
kubeadm upgrade node [flags]
选项 --certificate-renewal 对升级期间变化的组件所使用的证书执行更新。 --dry-run 不更改任何状态,只输出将要执行的操作。 --etcd-upgrade 默认值: true 执行 etcd 的升级。 --experimental-patches string 包含名为 "target[suffix][+patchtype].extension" 的文件的目录的路径。
例如,"kube-apiserver0+merge.yaml" 或仅仅是 "etcd.json"。
"patchtype" 可以是 "strategic"、"merge" 或 "json" 之一,并且它们与 kubectl 支持的补丁格式匹配。
默认的 "patchtype" 为 "strategic"。 "extension" 必须为 "json" 或 "yaml"。
"suffix" 是一个可选字符串,可用于确定首先按字母顺序应用哪些补丁。 -h, --help node 操作的帮助命令 --kubeconfig string 默认值: "/etc/kubernetes/admin.conf" 用于与集群交互的 kubeconfig 文件。如果参数未指定,将从一系列标准位置检索存在的 kubeconfig 文件。 --kubelet-version string 升级后 *期望的* kubelet 配置版本。如未指定,将使用 kubeadm-config ConfigMap 中的 KubernetesVersion --skip-phases stringSlice 要跳过的阶段的列表
从父命令继承的选项 --rootfs string [实验] 指向 '真实' 宿主机根文件系统的路径。
6.7.1.1.110 - 概要 使用此命令调用 node 工作流的某个阶段
选项 从父命令继承的选项 --rootfs string [实验] 指向 '真实' 宿主机根文件系统的路径。
6.7.1.1.111 - 概要 升级部署在此节点上的控制平面实例,如果有的话
kubeadm upgrade node phase control-plane [flags]
选项 --certificate-renewal 更新在升级期间变更的组件使用的证书。 --dry-run 不改变任何状态,只输出将要执行的动作。 --etcd-upgrade 默认值: true 执行 etcd 的升级。 --experimental-patches string 包含名为 "target[suffix][+patchtype].extension" 的文件的目录的路径。
例如,"kube-apiserver0+merge.yaml" 或仅仅是 "etcd.json"。
"patchtype" 可以是 "strategic"、"merge" 或 "json" 之一,并且它们与 kubectl 支持的补丁格式匹配。
默认的 "patchtype" 为 "strategic"。 "extension" 必须为 "json" 或 "yaml"。
"suffix" 是一个可选字符串,可用于确定首先按字母顺序应用哪些补丁。 -h, --help control-plane 的帮助信息 --kubeconfig string 默认值: "/etc/kubernetes/admin.conf" 用于和集群通信的 KubeConfig 文件。如果它没有被设置,那么 kubeadm 将会搜索一个已经存在于标准路径的 KubeConfig 文件。
从父命令继承的选项 --rootfs string [实验] 到'真实'主机根文件系统的路径。
6.7.1.1.112 - 从群集中 "kubelet-config-1.X" 的 ConfigMap 下载 kubelet 配置,其中 X 是kubelet 的次要版本。
kubeadm 使用 --kubelet-version 参数来确定所需的 kubelet 版本。
kubeadm upgrade node phase kubelet-config [flags]
选项 --dry-run 不改变任何状态,只输出将要执行的操作 -h, --help 配置操作的帮助信息 --kubeconfig string 默认值: "/etc/kubernetes/kubelet.conf" 用于和集群通信的 KubeConfig 文件。如果它没有被设置,那么 kubeadm 将会搜索一个已经存在于标准路径的 KubeConfig 文件。 --kubelet-version string 升级后的 kubelet 的*期望*版本。
从父命令继承的选项 --rootfs string [实验] 到'真实'主机根文件系统的路径。
6.7.1.1.113 - 执行 kubeadm 升级节点的预检。
kubeadm upgrade node phase preflight [flags]
选项 -h, --help preflight 操作的帮助命令 --ignore-preflight-errors stringSlice 错误将显示为警告的检查清单。示例:'IsPrivilegedUser,Swap'。值为'all'表示忽略所有检查的错误。
继承于父命令的选项 --rootfs string [实验] 到'真实'主机根文件系统的路径。
6.7.1.1.114 - 概述 检查可升级到哪些版本,并验证您当前的集群是否可升级。 要跳过互联网检查,请传递可选的 [version] 参数
kubeadm upgrade plan [version] [flags]
选项 --allow-experimental-upgrades 显示不稳定版本的 Kubernetes 作为升级替代方案,并允许升级到 Kubernetes 的 Alpha/Beta/发行候选版本。 --allow-release-candidate-upgrades 显示 Kubernetes 的发行候选版本作为升级选择,并允许升级到 Kubernetes 的发行候选版本。 --config string 配置文件的路径。 --feature-gates string 一组描述各种特征特性门控的键值对。选项有:IPv6DualStack=true|false (ALPHA - default=false) PublicKeysECDSA=true|false (ALPHA - default=false) -h, --help 帮助 --ignore-preflight-errors stringSlice 检查清单,其错误将显示为警告。 例如:“IsPrivilegedUser,Swap”。 值 “all” 忽略所有检查的错误。 --kubeconfig string Default: "/etc/kubernetes/admin.conf" 与集群通信时使用的 kubeconfig 文件。 如果标志为未设置,则可以在一组标准位置中搜索现有的 kubeconfig 文件。 --print-config 指定是否打印将在升级中使用的配置文件。
从父命令继承的选项 --rootfs string [EXPERIMENTAL] “真实”主机根文件系统的路径。
6.7.1.1.115 - 概要 打印 kubeadm 的版本
kubeadm version [flags]
选项 -h, --help version 操作的帮助命令 -o, --output string 输出格式;可用的选项有 'yaml', 'json' 和 'short'
从父命令继承的选项 --rootfs string [实验] 指向 '真实' 宿主机根文件系统的路径。
6.7.1.1.116 - 此目录下的所有文件都是从其他仓库自动生成的。 不要人工编辑它们。 您必须在上游仓库中编辑它们
6.7.1.2 - kubeadm init 此命令初始化一个 Kubernetes 控制平面节点。
概要 运行此命令来搭建 Kubernetes 控制平面节点。
"init" 命令执行以下阶段:
preflight Run pre-flight checks
certs Certificate generation
/ca Generate the self-signed Kubernetes CA to provision identities for other Kubernetes components
/apiserver Generate the certificate for serving the Kubernetes API
/apiserver-kubelet-client Generate the certificate for the API server to connect to kubelet
/front-proxy-ca Generate the self-signed CA to provision identities for front proxy
/front-proxy-client Generate the certificate for the front proxy client
/etcd-ca Generate the self-signed CA to provision identities for etcd
/etcd-server Generate the certificate for serving etcd
/etcd-peer Generate the certificate for etcd nodes to communicate with each other
/etcd-healthcheck-client Generate the certificate for liveness probes to healthcheck etcd
/apiserver-etcd-client Generate the certificate the apiserver uses to access etcd
/sa Generate a private key for signing service account tokens along with its public key
kubeconfig Generate all kubeconfig files necessary to establish the control plane and the admin kubeconfig file
/admin Generate a kubeconfig file for the admin to use and for kubeadm itself
/kubelet Generate a kubeconfig file for the kubelet to use *only* for cluster bootstrapping purposes
/controller-manager Generate a kubeconfig file for the controller manager to use
/scheduler Generate a kubeconfig file for the scheduler to use
kubelet-start Write kubelet settings and (re)start the kubelet
control-plane Generate all static Pod manifest files necessary to establish the control plane
/apiserver Generates the kube-apiserver static Pod manifest
/controller-manager Generates the kube-controller-manager static Pod manifest
/scheduler Generates the kube-scheduler static Pod manifest
etcd Generate static Pod manifest file for local etcd
/local Generate the static Pod manifest file for a local, single-node local etcd instance
upload-config Upload the kubeadm and kubelet configuration to a ConfigMap
/kubeadm Upload the kubeadm ClusterConfiguration to a ConfigMap
/kubelet Upload the kubelet component config to a ConfigMap
upload-certs Upload certificates to kubeadm-certs
mark-control-plane Mark a node as a control-plane
bootstrap-token Generates bootstrap tokens used to join a node to a cluster
kubelet-finalize Updates settings relevant to the kubelet after TLS bootstrap
/experimental-cert-rotation Enable kubelet client certificate rotation
addon Install required addons for passing Conformance tests
/coredns Install the CoreDNS addon to a Kubernetes cluster
/kube-proxy Install the kube-proxy addon to a Kubernetes cluster
kubeadm init [flags]
选项 --apiserver-advertise-address string API 服务器所公布的其正在监听的 IP 地址。如果未设置,则使用默认网络接口。 --apiserver-bind-port int32 默认值:6443 API 服务器绑定的端口。 --apiserver-cert-extra-sans stringSlice 用于 API Server 服务证书的可选附加主题备用名称(SAN)。可以是 IP 地址和 DNS 名称。 --cert-dir string 默认值:"/etc/kubernetes/pki" 保存和存储证书的路径。 --certificate-key string 用于加密 kubeadm-certs Secret 中的控制平面证书的密钥。 --config string kubeadm 配置文件的路径。 --control-plane-endpoint string 为控制平面指定一个稳定的 IP 地址或 DNS 名称。 --cri-socket string 要连接的 CRI 套接字的路径。如果为空,则 kubeadm 将尝试自动检测此值;仅当安装了多个 CRI 或具有非标准 CRI 插槽时,才使用此选项。 --dry-run 不要应用任何更改;只是输出将要执行的操作。 --experimental-patches string 包含名为 "target[suffix][+patchtype].extension" 的文件的目录路径。
例如,"kube-apiserver0+merge.yaml" 或仅仅是 "etcd.json"。
"patchtype" 可以是 "strategic"、"merge" 或 "json" 之一,并且它们与 kubectl 支持的补丁格式匹配。
默认的 "patchtype" 为 "strategic"。 "extension" 必须为 "json" 或 "yaml"。
"suffix" 是一个可选字符串,可用于确定首先按字母顺序应用哪些补丁。 --feature-gates string 一组用来描述各种功能特性的键值(key=value)对。选项是: IPv6DualStack=true|false (ALPHA - default=false) -h, --help init 操作的帮助命令 --ignore-preflight-errors stringSlice 错误将显示为警告的检查列表;例如:'IsPrivilegedUser,Swap'。取值为 'all' 时将忽略检查中的所有错误。 --image-repository string 默认值:"k8s.gcr.io" 选择用于拉取控制平面镜像的容器仓库 --kubernetes-version string 默认值:"stable-1" 为控制平面选择一个特定的 Kubernetes 版本。 --node-name string 指定节点的名称。 --pod-network-cidr string 指明 pod 网络可以使用的 IP 地址段。如果设置了这个参数,控制平面将会为每一个节点自动分配 CIDRs。 --service-cidr string 默认值:"10.96.0.0/12" 为服务的虚拟 IP 地址另外指定 IP 地址段 --service-dns-domain string 默认值:"cluster.local" 为服务另外指定域名,例如:"myorg.internal"。 --skip-certificate-key-print 不要打印用于加密控制平面证书的密钥。 --skip-phases stringSlice 要跳过的阶段列表 --skip-token-print 跳过打印 'kubeadm init' 生成的默认引导令牌。 --token string 这个令牌用于建立控制平面节点与工作节点间的双向通信。格式为 [a-z0-9]{6}\.[a-z0-9]{16} - 示例:abcdef.0123456789abcdef --token-ttl duration 默认值:24h0m0s 令牌被自动删除之前的持续时间(例如 1 s,2 m,3 h)。如果设置为 '0',则令牌将永不过期 --upload-certs 将控制平面证书上传到 kubeadm-certs Secret。
从父命令继承的选项 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
Init 命令的工作流程 kubeadm init 命令通过执行下列步骤来启动一个 Kubernetes 控制平面节点。
在做出变更前运行一系列的预检项来验证系统状态。一些检查项目仅仅触发警告,
其它的则会被视为错误并且退出 kubeadm,除非问题得到解决或者用户指定了
--ignore-preflight-errors=<错误列表> 参数。 生成一个自签名的 CA 证书来为集群中的每一个组件建立身份标识。
用户可以通过将其放入 --cert-dir 配置的证书目录中(默认为 /etc/kubernetes/pki)
来提供他们自己的 CA 证书以及/或者密钥。
APIServer 证书将为任何 --apiserver-cert-extra-sans 参数值提供附加的 SAN 条目,必要时将其小写。 将 kubeconfig 文件写入 /etc/kubernetes/ 目录以便 kubelet、控制器管理器和调度器用来连接到
API 服务器,它们每一个都有自己的身份标识,同时生成一个名为 admin.conf 的独立的 kubeconfig
文件,用于管理操作。 为 API 服务器、控制器管理器和调度器生成静态 Pod 的清单文件。假使没有提供一个外部的 etcd
服务的话,也会为 etcd 生成一份额外的静态 Pod 清单文件。
静态 Pod 的清单文件被写入到 /etc/kubernetes/manifests 目录;
kubelet 会监视这个目录以便在系统启动的时候创建 Pod。
一旦控制平面的 Pod 都运行起来, kubeadm init 的工作流程就继续往下执行。
对控制平面节点应用标签和污点标记以便不会在它上面运行其它的工作负载。 生成令牌,将来其他节点可使用该令牌向控制平面注册自己。
如 kubeadm token 文档所述,
用户可以选择通过 --token 提供令牌。 为了使得节点能够遵照启动引导令牌
和 TLS 启动引导
这两份文档中描述的机制加入到集群中,kubeadm 会执行所有的必要配置:
更多相关信息,请查看 kubeadm join 。
通过 API 服务器安装一个 DNS 服务器 (CoreDNS) 和 kube-proxy 附加组件。
在 Kubernetes 版本 1.11 和更高版本中,CoreDNS 是默认的 DNS 服务器。
要安装 kube-dns 而不是 CoreDNS,必须在 kubeadm ClusterConfiguration 中配置 DNS 插件。
有关配置的更多信息,请参见下面的"带配置文件使用 kubeadm init" 一节。
请注意,尽管已部署 DNS 服务器,但直到安装 CNI 时才调度它。
警告: 从 v1.18 开始,在 kubeadm 中使用 kube-dns 已废弃,并将在以后的版本中将其删除。
在 kubeadm 中使用 init phases Kubeadm 允许你使用 kubeadm init phase 命令分阶段创建控制平面节点。
要查看阶段和子阶段的有序列表,可以调用 kubeadm init --help。
该列表将位于帮助屏幕的顶部,每个阶段旁边都有一个描述。
注意,通过调用 kubeadm init,所有阶段和子阶段都将按照此确切顺序执行。
某些阶段具有唯一的标志,因此,如果要查看可用选项的列表,请添加 --help,例如:
sudo kubeadm init phase control-plane controller-manager --help
你也可以使用 --help 查看特定父阶段的子阶段列表:
sudo kubeadm init phase control-plane --help
kubeadm init 还公开了一个名为 --skip-phases 的参数,该参数可用于跳过某些阶段。
参数接受阶段名称列表,并且这些名称可以从上面的有序列表中获取。
例如:
sudo kubeadm init phase control-plane all --config= configfile.yaml
sudo kubeadm init phase etcd local --config= configfile.yaml
# 你现在可以修改控制平面和 etcd 清单文件
sudo kubeadm init --skip-phases= control-plane,etcd --config= configfile.yaml
该示例将执行的操作是基于 configfile.yaml 中的配置在 /etc/kubernetes/manifests
中写入控制平面和 etcd 的清单文件。
这允许你修改文件,然后使用 --skip-phases 跳过这些阶段。
通过调用最后一个命令,你将使用自定义清单文件创建一个控制平面节点。
结合一份配置文件来使用 kubeadm init 注意: 配置文件的功能仍然处于 alpha 状态并且在将来的版本中可能会改变。
通过一份配置文件而不是使用命令行参数来配置 kubeadm init 命令是可能的,
但是一些更加高级的功能只能够通过配置文件设定。
这份配置文件通过 --config 选项参数指定的,
它必须包含 ClusterConfiguration 结构,并可能包含更多由 ---\n 分隔的结构。
在某些情况下,可能不允许将 --config 与其他标志混合使用。
可以使用 kubeadm config print
命令打印出默认配置。
如果你的配置没有使用最新版本,
推荐 使用 kubeadm config migrate
命令进行迁移。
有关配置的字段和用法的更多信息,
你可以访问 API 参考页面并从
列表
中选择一个版本。
添加 kube-proxy 参数 kubeadm 配置中有关 kube-proxy 的说明请查看:
使用 kubeadm 启用 IPVS 模式的说明请查看:
向控制平面组件传递自定义的命令行参数 有关向控制平面组件传递命令行参数的说明请查看:
控制平面命令行参数
使用自定义的镜像 默认情况下, kubeadm 会从 k8s.gcr.io 仓库拉取镜像。如果请求的 Kubernetes 版本是 CI 标签
(例如 ci/latest),则使用 gcr.io/kubernetes-ci-images。
你可以通过使用带有配置文件的 kubeadm 来重写此操作。
允许的自定义功能有:
使用其他的 imageRepository 来代替 k8s.gcr.io。 将 useHyperKubeImage 设置为 true,使用 HyperKube 镜像。 为 etcd 或 DNS 附件提供特定的 imageRepository 和 imageTag。 请注意配置文件中的配置项 kubernetesVersion 或者命令行参数 --kubernetes-version
会影响到镜像的版本。
将控制平面证书上传到集群 通过将参数 --upload-certs 添加到 kubeadm init,你可以将控制平面证书临时上传到集群中的 Secret。
请注意,此 Secret 将在 2 小时后自动过期。证书使用 32 字节密钥加密,可以使用 --certificate-key 指定。
通过将 --control-plane 和 --certificate-key 传递给 kubeadm join,
可以在添加其他控制平面节点时使用相同的密钥下载证书。
以下阶段命令可用于证书到期后重新上传证书:
kubeadm init phase upload-certs --upload-certs --certificate-key= SOME_VALUE --config= SOME_YAML_FILE
如果未将参数 --certificate-key 传递给 kubeadm init 和 kubeadm init phase upload-certs,
则会自动生成一个新密钥。
以下命令可用于按需生成新密钥:
kubeadm certs certificate-key
使用 kubeadm 管理证书 有关使用 kubeadm 进行证书管理的详细信息,请参阅
使用 kubeadm 进行证书管理 。
该文档包括有关使用外部 CA,自定义证书和证书更新的信息。
管理 kubeadm 为 kubelet 提供的 systemd 配置文件 kubeadm 包自带了关于 systemd 如何运行 kubelet 的配置文件。
请注意 kubeadm 客户端命令行工具永远不会修改这份 systemd 配置文件。
这份 systemd 配置文件属于 kubeadm DEB/RPM 包。
有关更多信息,请阅读
管理 systemd 的 kubeadm 内嵌文件 。
结合 CRI 运行时使用 kubeadm 默认情况下,kubeadm 尝试检测你的容器运行环境。有关此检测的更多详细信息,请参见
kubeadm CRI 安装指南 。
设置节点的名称 默认情况下, kubeadm 基于机器的主机地址分配一个节点名称。你可以使用 --node-name 参数覆盖此设置。
此标识将合适的
--hostname-override
值传递给 kubelet。
在没有互联网连接的情况下运行 kubeadm 要在没有互联网连接的情况下运行 kubeadm,你必须提前拉取所需的控制平面镜像。
你可以使用 kubeadm config images 子命令列出并拉取镜像:
kubeadm config images list
kubeadm config images pull
kubeadm 需要的所有镜像,例如 k8s.gcr.io/kube-*、k8s.gcr.io/etcd 和 k8s.gcr.io/pause
都支持多种架构。
kubeadm 自动化 除了像文档 kubeadm 基础教程
中所描述的那样,将从 kubeadm init 取得的令牌复制到每个节点,
你还可以并行地分发令牌以实现简单自动化。
要实现自动化,你必须知道控制平面节点启动后将拥有的 IP 地址,或使用 DNS 名称或负载均衡器的地址。
生成一个令牌。这个令牌必须具有以下格式:< 6 个字符的字符串>.< 16 个字符的字符串>。
更加正式的说法是,它必须符合以下正则表达式:[a-z0-9]{6}\.[a-z0-9]{16}。
kubeadm 可以为你生成一个令牌:
使用这个令牌同时启动控制平面节点和工作节点。它们一旦运行起来应该就会互相寻找对方并且建立集群。
同样的 --token 参数可以同时用于 kubeadm init 和 kubeadm join 命令。 当加入其他控制平面节点时,可以对 --certificate-key 执行类似的操作。可以使用以下方式生成密钥:
kubeadm certs certificate-key
一旦集群启动起来,你就可以从控制平面节点的 /etc/kubernetes/admin.conf 文件获取管理凭证,
并使用这个凭证同集群通信。
注意这种搭建集群的方式在安全保证上会有一些宽松,因为这种方式不允许使用 --discovery-token-ca-cert-hash
来验证根 CA 的哈希值(因为当配置节点的时候,它还没有被生成)。
更多信息请参阅 kubeadm join 文档。
接下来 6.7.1.3 - kubeadm join 此命令用来初始化 Kubernetes 工作节点并将其加入集群。
摘要 当节点加入 kubeadm 初始化的集群时,我们需要建立双向信任。
这个过程可以分解为发现(让待加入节点信任 Kubernetes 控制平面节点)和 TLS 引导(让Kubernetes 控制平面节点信任待加入节点)两个部分。
有两种主要的发现方案。
第一种方法是使用共享令牌和 API 服务器的 IP 地址。
第二种是提供一个文件 - 标准 kubeconfig 文件的一个子集。
该文件可以是本地文件,也可以通过 HTTPS URL 下载。
格式是 kubeadm join --discovery-token abcdef.1234567890abcdef 1.2.3.4:6443、kubeadm join--discovery-file path/to/file.conf 或者kubeadm join --discovery-file https://url/file.conf。
只能使用其中一种。
如果发现信息是从 URL 加载的,必须使用 HTTPS。
此外,在这种情况下,主机安装的 CA 包用于验证连接。
如果使用共享令牌进行发现,还应该传递 --discovery-token-ca-cert-hash 参数来验证 Kubernetes 控制平面节点提供的根证书颁发机构(CA)的公钥。
此参数的值指定为 "<hash-type>:<hex-encoded-value>",其中支持的哈希类型为 "sha256"。哈希是通过 Subject Public Key Info(SPKI)对象的字节计算的(如 RFC7469)。
这个值可以从 "kubeadm init" 的输出中获得,或者可以使用标准工具进行计算。
可以多次重复 --discovery-token-ca-cert-hash 参数以允许多个公钥。
如果无法提前知道 CA 公钥哈希,则可以通过 --discovery-token-unsafe-skip-ca-verification 参数禁用此验证。
这削弱了kubeadm 安全模型,因为其他节点可能会模仿 Kubernetes 控制平面节点。
TLS 引导机制也通过共享令牌驱动。
这用于向 Kubernetes 控制平面节点进行临时的身份验证,以提交本地创建的密钥对的证书签名请求(CSR)。
默认情况下,kubeadm 将设置 Kubernetes 控制平面节点自动批准这些签名请求。
这个令牌通过 --tls-bootstrap-token abcdef.1234567890abcdef 参数传入。
通常两个部分会使用相同的令牌。
在这种情况下可以使用 --token 参数,而不是单独指定每个令牌。
"join [api-server-endpoint]" 命令执行下列阶段:
preflight Run join pre-flight checks
control-plane-prepare Prepare the machine for serving a control plane
/download-certs [EXPERIMENTAL] Download certificates shared among control-plane nodes from the kubeadm-certs Secret
/certs Generate the certificates for the new control plane components
/kubeconfig Generate the kubeconfig for the new control plane components
/control-plane Generate the manifests for the new control plane components
kubelet-start Write kubelet settings, certificates and (re)start the kubelet
control-plane-join Join a machine as a control plane instance
/etcd Add a new local etcd member
/update-status Register the new control-plane node into the ClusterStatus maintained in the kubeadm-config ConfigMap
/mark-control-plane Mark a node as a control-plane
kubeadm join [api-server-endpoint] [flags]
选项 --apiserver-advertise-address string 如果该节点托管一个新的控制平面实例,则 API 服务器将公布其正在侦听的 IP 地址。如果未设置,则使用默认网络接口。 --apiserver-bind-port int32 默认值: 6443 如果节点应该托管新的控制平面实例,则为 API 服务器要绑定的端口。 --certificate-key string 使用此密钥可以解密由 init 上传的证书 secret。 --config string kubeadm 配置文件的路径。 --control-plane 在此节点上创建一个新的控制平面实例 --cri-socket string 要连接的 CRI 套接字的路径。如果为空,则 kubeadm 将尝试自动检测此值;仅当安装了多个 CRI 或具有非标准 CRI 插槽时,才使用此选项。 --discovery-file string 对于基于文件的发现,给出用于加载集群信息的文件或者 URL。 --discovery-token string 对于基于令牌的发现,该令牌用于验证从 API 服务器获取的集群信息。 --discovery-token-ca-cert-hash stringSlice 对基于令牌的发现,验证根 CA 公钥是否与此哈希匹配 (格式: "<type>:<value>")。 --discovery-token-unsafe-skip-ca-verification 对于基于令牌的发现,允许在未关联 --discovery-token-ca-cert-hash 参数的情况下添加节点。 --experimental-patches string 包含名为 "target[suffix][+patchtype].extension" 的文件的目录的路径。
例如,"kube-apiserver0+merge.yaml" 或仅仅是 "etcd.json"。
"patchtype" 可以是 "strategic"、"merge" 或 "json" 之一,并且它们与 kubectl 支持的补丁格式匹配。
默认的 "patchtype" 为 "strategic"。 "extension" 必须为 "json" 或 "yaml"。
"suffix" 是一个可选字符串,可用于确定首先按字母顺序应用哪些补丁。 -h, --help join 操作的帮助命令 --ignore-preflight-errors stringSlice 错误将显示为警告的检查列表;例如:'IsPrivilegedUser,Swap'。取值为 'all' 时将忽略检查中的所有错误。 --node-name string 指定节点的名称 --skip-phases stringSlice 要跳过的阶段列表 --tls-bootstrap-token string 指定在加入节点时用于临时通过 Kubernetes 控制平面进行身份验证的令牌。 --token string 如果未提供这些值,则将它们用于 discovery-token 令牌和 tls-bootstrap 令牌。
从父命令继承的选项 --rootfs string [实验] 指向 '真实' 宿主机根文件系统的路径。
join 工作流 kubeadm join 初始化 Kubernetes 工作节点并将其加入集群。
该操作过程包含下面几个步骤:
kubeadm 从 API 服务器下载必要的集群信息。
默认情况下,它使用引导令牌和 CA 密钥哈希来验证数据的真实性。
也可以通过文件或 URL 直接发现根 CA。 一旦知道集群信息,kubelet 就可以开始 TLS 引导过程。
TLS 引导程序使用共享令牌与 Kubernetes API 服务器进行临时的身份验证,以提交证书签名请求 (CSR);
默认情况下,控制平面自动对该 CSR 请求进行签名。
最后,kubeadm 配置本地 kubelet 使用分配给节点的确定标识连接到 API 服务器。 对于控制平面节点,执行额外的步骤:
从集群下载控制平面节点之间共享的证书(如果用户明确要求)。
生成控制平面组件清单、证书和 kubeconfig。
添加新的本地 etcd 成员。
将此节点添加到 kubeadm 集群的 ClusterStatus。
使用 kubeadm 的 join phase 命令 Kubeadm 允许你使用 kubeadm join phase 分阶段将节点加入集群。
要查看阶段和子阶段的有序列表,可以调用 kubeadm join --help。
该列表将位于帮助屏幕的顶部,每个阶段旁边都有一个描述。
注意,通过调用 kubeadm join,所有阶段和子阶段都将按照此确切顺序执行。
有些阶段具有唯一的标志,因此,如果要查看可用选项列表,请添加 --help,例如:
kubeadm join phase kubelet-start --help
类似于 kubeadm init phase 命令,
kubeadm join phase 允许你使用 --skip-phases 标志跳过阶段列表。
例如:
sudo kubeadm join --skip-phases= preflight --config= config.yaml
发现要信任的集群 CA Kubeadm 的发现有几个选项,每个选项都有安全性上的优缺点。
适合你的环境的正确方法取决于节点是如何准备的以及你对网络的安全性期望和节点的生命周期特点。
带 CA 锁定模式的基于令牌的发现 这是 Kubernetes 1.8 及以上版本中的默认模式。
在这种模式下,kubeadm 下载集群配置(包括根CA)并使用令牌验证它,
并且会验证根 CA 的公钥与所提供的哈希是否匹配,
以及 API 服务器证书在根 CA 下是否有效。
CA 键哈希格式为 sha256:<hex_encoded_hash>。
默认情况下,在 kubeadm init 最后打印的 kubeadm join 命令
或者 kubeadm token create --print-join-command 的输出信息中返回哈希值。
它使用标准格式 (请参考 RFC7469 )
并且也能通过第三方工具或者制备系统进行计算。
例如,使用 OpenSSL CLI:
openssl x509 -pubkey -in /etc/kubernetes/pki/ca.crt | openssl rsa -pubin -outform der 2>/dev/null | openssl dgst -sha256 -hex | sed 's/^.* //'
kubeadm join 命令示例
对于工作节点:
kubeadm join --discovery-token abcdef.1234567890abcdef --discovery-token-ca-cert-hash sha256:1234..cdef 1.2.3.4:6443
对于控制面节点:
kubeadm join --discovery-token abcdef.1234567890abcdef --discovery-token-ca-cert-hash sha256:1234..cdef --control-plane 1.2.3.4:6443
如果使用 --upload-certs 调用 kubeadm init 命令,
你也可以对控制平面节点调用带 --certificate-key 参数的 join 命令,
将证书复制到该节点。
优势:
劣势:
CA 哈希通常在主节点被提供之前是不知道的,这使得构建使用 kubeadm 的自动化配置工具更加困难。
通过预先生成CA,你可以解除这个限制。 无 CA 锁定模式的基于令牌的发现 _这是 Kubernetes 1.7 和早期版本_中的默认设置;使用时要注意一些重要的补充说明。
此模式仅依赖于对称令牌来签名(HMAC-SHA256)发现信息,这些发现信息为主节点建立信任根。
在 Kubernetes 1.8 及以上版本中仍然可以使用 --discovery-token-unsafe-skip-ca-verification 参数,但是如果可能的话,你应该考虑使用一种其他模式。
kubeadm join 命令示例
kubeadm join --token abcdef.1234567890abcdef --discovery-token-unsafe-skip-ca-verification 1.2.3.4:6443
优势
劣势
如果攻击者能够通过某些漏洞窃取引导令牌,那么他们可以使用该令牌(连同网络级访问)为其它处于引导过程中的节点提供假冒的主节点。
在你的环境中,这可能是一个适当的折衷方法,也可能不是。 基于 HTTPS 或文件发现 这种方案提供了一种带外方式在主节点和引导节点之间建立信任根。
如果使用 kubeadm 构建自动配置,请考虑使用此模式。
发现文件的格式为常规的 Kubernetes kubeconfig 文件。
如果发现文件不包含凭据,则将使用 TLS 发现令牌。
kubeadm join 命令示例:
优势:
允许引导节点安全地发现主节点的信任根,即使网络或其他工作节点受到损害。 劣势:
要求你有某种方法将发现信息从主节点传送到引导节点。
例如,这可以通过云提供商或驱动工具实现。
该文件中的信息不是加密的,而是需要 HTTPS 或等效文件来保证其完整性。 确保你的安装更加安全 Kubeadm 的默认值可能不适用于所有人。
本节说明如何以牺牲可用性为代价来加强 kubeadm 安装。
关闭节点客户端证书的自动批准 默认情况下,Kubernetes 启用了 CSR 自动批准器,如果在身份验证时使用 Bootstrap Token,它会批准对 kubelet 的任何客户端证书的请求。
如果不希望集群自动批准kubelet客户端证书,可以通过执行以下命令关闭它:
kubectl delete clusterrolebinding kubeadm:node-autoapprove-bootstrap
关闭后,kubeadm join 操作将会被阻断,直到管理员已经手动批准了在途中的 CSR 才会继续:
输出类似于:
NAME AGE REQUESTOR CONDITION
node-csr-c69HXe7aYcqkS1bKmH4faEnHAWxn6i2bHZ2mD04jZyQ 18s system:bootstrap:878f07 Pending
kubectl certificate approve node-csr-c69HXe7aYcqkS1bKmH4faEnHAWxn6i2bHZ2mD04jZyQ
输出类似于:
certificatesigningrequest "node-csr-c69HXe7aYcqkS1bKmH4faEnHAWxn6i2bHZ2mD04jZyQ" approved
输出类似于:
NAME AGE REQUESTOR CONDITION
node-csr-c69HXe7aYcqkS1bKmH4faEnHAWxn6i2bHZ2mD04jZyQ 1m system:bootstrap:878f07 Approved,Issued
这迫使工作流只有在运行了 kubectl 证书批准后,kubeadm join 才能成功。
关闭对集群信息 ConfigMap 的公开访问 为了实现使用令牌作为唯一验证信息的加入工作流,默认情况下会公开带有验证主节点标识所需数据的 ConfigMap。
虽然此 ConfigMap 中没有私有数据,但一些用户可能希望无论如何都关闭它。
这样做需要禁用 kubeadm join 工作流的 --discovery-token 参数。
以下是实现步骤:
从 API 服务器获取 cluster-info 文件: kubectl -n kube-public get cm cluster-info -o yaml | grep "kubeconfig:" -A11 | grep "apiVersion" -A10 | sed "s/ //" | tee cluster-info.yaml
输出类似于:
apiVersion: v1
kind: Config
clusters:
- cluster:
certificate-authority-data: <ca-cert>
server: https://<ip>:<port>
name: ""
contexts: []
current-context: ""
preferences: {}
users: []
kubectl -n kube-public delete rolebinding kubeadm:bootstrap-signer-clusterinfo
这些命令应该在执行 kubeadm init 之后、在kubeadm join 之前执行。
使用带有配置文件的 kubeadm join 注意: 配置文件目前是 alpha 功能,在将来的版本中可能会变动。
可以用配置文件替代命令行参数的方法配置 kubeadm join,一些高级功能也只有在使用配置文件时才可选用。
该文件通过 --config 参数来传递,并且文件中必须包含 JoinConfiguration 结构。
在某些情况下,不允许将 --config 与其他标志混合使用。
使用 kubeadm config print
命令可以打印默认配置。
如果你的配置没有使用最新版本,
推荐 使用 kubeadm config migrate
命令转换。
有关配置的字段和用法的更多信息,你可以导航到我们的 API 参考页
并从[列表]中选择一个版本(https://godoc.org/k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm#pkg-subdirectories )。
接下来 6.7.1.4 - kubeadm upgrade kubeadm upgrade 是一个对用户友好的命令,它将复杂的升级逻辑包装在一个命令后面,支持升级的规划和实际执行。
kubeadm 升级指南 本文档 概述了使用 kubeadm 执行升级的步骤。
有关 kubeadm 旧版本,请参阅 Kubernetes 网站的旧版文档。
你可以使用 kubeadm upgrade diff 来查看将应用于静态 pod 清单的更改。
要在 Kubernetes v1.13.0 及更高版本中使用 kube-dns 进行升级,请遵循本指南 。
在 Kubernetes v1.15.0 和更高版本中,kubeadm upgrade apply 和 kubeadm upgrade node 也将自动续订该节点上的 kubeadm 托管证书,包括存储在 kubeconfig 文件中的证书。
要选择退出,可以传递参数 --certificate-renewal=false。有关证书续订的更多详细信息请参见证书管理文档 。
说明: kubeadm upgrade apply 和 kubeadm upgrade plan 命令都具有遗留的 --config 标志,
可以在执行特定控制平面节点的规划或升级时重新配置集群。
请注意,升级工作流不是为这种情况而设计的,并且有意外结果的报告。
kubeadm upgrade plan 概述 检查可升级到哪些版本,并验证您当前的集群是否可升级。 要跳过互联网检查,请传递可选的 [version] 参数
kubeadm upgrade plan [version] [flags]
选项 --allow-experimental-upgrades 显示不稳定版本的 Kubernetes 作为升级替代方案,并允许升级到 Kubernetes 的 Alpha/Beta/发行候选版本。 --allow-release-candidate-upgrades 显示 Kubernetes 的发行候选版本作为升级选择,并允许升级到 Kubernetes 的发行候选版本。 --config string 配置文件的路径。 --feature-gates string 一组描述各种特征特性门控的键值对。选项有:IPv6DualStack=true|false (ALPHA - default=false) PublicKeysECDSA=true|false (ALPHA - default=false) -h, --help 帮助 --ignore-preflight-errors stringSlice 检查清单,其错误将显示为警告。 例如:“IsPrivilegedUser,Swap”。 值 “all” 忽略所有检查的错误。 --kubeconfig string Default: "/etc/kubernetes/admin.conf" 与集群通信时使用的 kubeconfig 文件。 如果标志为未设置,则可以在一组标准位置中搜索现有的 kubeconfig 文件。 --print-config 指定是否打印将在升级中使用的配置文件。
从父命令继承的选项 --rootfs string [EXPERIMENTAL] “真实”主机根文件系统的路径。
kubeadm upgrade apply 概要 将 Kubernetes 集群升级到指定版本
kubeadm upgrade apply [version]
选项 --allow-experimental-upgrades 显示 Kubernetes 的不稳定版本作为升级替代方案,并允许升级到 Kubernetes 的 alpha/beta 或 RC 版本。 --allow-release-candidate-upgrades 显示 Kubernetes 的候选版本作为升级替代方案,并允许升级到 Kubernetes 的 RC 版本。 --certificate-renewal Default: true 执行升级期间更改的组件所使用的证书的更新。 --config string kubeadm 配置文件的路径。 --dry-run 不要更改任何状态,只输出要执行的操作。 --etcd-upgrade 默认值: true 执行 etcd 的升级。 --experimental-patches string 包含名为 "target[suffix][+patchtype].extension" 的文件的目录的路径。
例如,"kube-apiserver0+merge.yaml" 或仅仅是 "etcd.json"。
"patchtype" 可以是 "strategic"、"merge" 或 "json" 之一,并且它们与 kubectl 支持的补丁格式匹配。
默认的 "patchtype" 为 "strategic"。 "extension" 必须为 "json" 或 "yaml"。
"suffix" 是一个可选字符串,可用于确定首先按字母顺序应用哪些补丁。 --feature-gates string 一组键值对,用于描述各种功能。选项包括: IPv6DualStack=true|false (ALPHA - 默认=false) PublicKeysECDSA=true|false (ALPHA - 默认=false) -f, --force 强制升级,但可能无法满足某些要求。这也意味着非交互模式。 -h, --help apply 操作的帮助命令 --ignore-preflight-errors stringSlice 错误将显示为警告的检查列表;例如:'IsPrivilegedUser,Swap'。取值为 'all' 时将忽略检查中的所有错误。 --kubeconfig string 默认值:"/etc/kubernetes/admin.conf" 与集群通信时使用的 kubeconfig 文件。如果未设置标志,则在相关目录下搜索以查找现有 kubeconfig 文件。 --print-config 指定是否应打印将在升级中使用的配置文件。 -y, --yes 执行升级,不提示确认(非交互模式)。
从父命令继承的选项 --rootfs string [实验] 指向 '真实' 宿主机根文件系统的路径。
kubeadm upgrade diff 概述 显示哪些差异将被应用于现有的静态 pod 资源清单。参考: kubeadm upgrade apply --dry-run
kubeadm upgrade diff [version] [flags]
选项 --api-server-manifest string 默认值:"/etc/kubernetes/manifests/kube-apiserver.yaml" API服务器清单的路径 --config string kubeadm 配置文件的路径 -c, --context-lines int 默认值:3 差异中有多少行上下文 --controller-manager-manifest string 默认值: "/etc/kubernetes/manifests/kube-controller-manager.yaml" 控制器清单的路径 -h, --help 帮助 --kubeconfig string 默认值:"/etc/kubernetes/admin.conf" 与集群通信时使用的 kubeconfig 文件,如果标志是未设置,则可以在一组标准位置中搜索现有的 kubeconfig 文件。 --scheduler-manifest string 默认值:"/etc/kubernetes/manifests/kube-scheduler.yaml" 调度程序清单的路径
从父命令继承的选项 --rootfs string [EXPERIMENTAL] “真实”主机根文件系统的路径。
kubeadm upgrade node 概要 升级集群中某个节点的命令
"node" 命令执行以下阶段:
preflight 执行节点升级前检查
control-plane 如果存在的话,升级部署在该节点上的管理面实例
kubelet-config 更新该节点上的 kubelet 配置
kubeadm upgrade node [flags]
选项 --certificate-renewal 对升级期间变化的组件所使用的证书执行更新。 --dry-run 不更改任何状态,只输出将要执行的操作。 --etcd-upgrade 默认值: true 执行 etcd 的升级。 --experimental-patches string 包含名为 "target[suffix][+patchtype].extension" 的文件的目录的路径。
例如,"kube-apiserver0+merge.yaml" 或仅仅是 "etcd.json"。
"patchtype" 可以是 "strategic"、"merge" 或 "json" 之一,并且它们与 kubectl 支持的补丁格式匹配。
默认的 "patchtype" 为 "strategic"。 "extension" 必须为 "json" 或 "yaml"。
"suffix" 是一个可选字符串,可用于确定首先按字母顺序应用哪些补丁。 -h, --help node 操作的帮助命令 --kubeconfig string 默认值: "/etc/kubernetes/admin.conf" 用于与集群交互的 kubeconfig 文件。如果参数未指定,将从一系列标准位置检索存在的 kubeconfig 文件。 --kubelet-version string 升级后 *期望的* kubelet 配置版本。如未指定,将使用 kubeadm-config ConfigMap 中的 KubernetesVersion --skip-phases stringSlice 要跳过的阶段的列表
从父命令继承的选项 --rootfs string [实验] 指向 '真实' 宿主机根文件系统的路径。
接下来 如果你使用 kubeadm v1.7.x 或更低版本初始化集群,则可以参考kubeadm 配置 配置集群用于 kubeadm upgrade。 6.7.1.5 - kubeadm config 在 kubeadm init 执行期间,kubeadm 将 ClusterConfiguration 对象上传到你的集群的 kube-system 名字空间下
名为 kubeadm-config 的 ConfigMap 对象中。
然后在 kubeadm join、kubeadm reset 和 kubeadm upgrade 执行期间读取此配置。
要查看此 ConfigMap,请调用 kubeadm config view。
你可以使用 kubeadm config print 命令打印默认配置,
并使用 kubeadm config migrate 命令将旧版本的配置转化成新版本。
kubeadm config images list 和 kubeadm config images pull
命令可以用来列出并拉取 kubeadm 所需的镜像。
更多信息请浏览使用带配置文件的 kubeadm init
或使用带配置文件的 kubeadm join .
在 Kubernetes v1.13.0 及更高版本中,要列出/拉取 kube-dns 镜像而不是 CoreDNS 镜像,
必须使用这里 所描述的 --config 方法。
kubeadm config upload from-file kubeadm config view 概要 使用此命令,可以查看 kubeadm 配置的集群中的 ConfigMap。
该配置位于 "kube-system" 命名空间中的名为 "kubeadm-config" 的 ConfigMap 中。
kubeadm config view [flags]
选项 继承于父命令的选项 --kubeconfig string 默认值:"/etc/kubernetes/admin.conf" 用于和集群通信的 KubeConfig 文件。如果未设置,那么 kubeadm 将会搜索一个已经存在于标准路径的 KubeConfig 文件。 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
kubeadm config print init-defaults 概要 此命令打印对象,例如用于 'kubeadm init' 的默认 init 配置对象。
请注意,Bootstrap Token 字段之类的敏感值已替换为 {"abcdef.0123456789abcdef" "" "nil" <nil> [] []} 之类的占位符值以通过验证,但不执行创建令牌的实际计算。
kubeadm config print init-defaults [flags]
选项 --component-configs stringSlice 组件配置 API 对象的逗号分隔列表,打印其默认值。可用值:[KubeProxyConfiguration KubeletConfiguration]。如果未设置此参数,则不会打印任何组件配置。 -h, --help init-defaults 操作的帮助命令
从父命令继承的选项 --kubeconfig string 默认值:"/etc/kubernetes/admin.conf" 与集群通信时使用的 kubeconfig 文件。如果未设置该参数,则可以在一组标准位置中搜索现有的 kubeconfig 文件。 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
kubeadm config print join-defaults 概要 此命令打印对象,例如用于 'kubeadm join' 的默认 join 配置对象。
请注意,诸如启动引导令牌字段之类的敏感值已替换为 {"abcdef.0123456789abcdef" "" "nil" <nil> [] []}
之类的占位符值以通过验证,但不执行创建令牌的实际计算。
kubeadm config print join-defaults [flags]
选项 --component-configs stringSlice 组件配置 API 对象的逗号分隔列表,打印其默认值。可用值:[KubeProxyConfiguration KubeletConfiguration]。如果未设置此参数,则不会打印任何组件配置。 -h, --help join-defaults 操作的帮助命令
从父命令继承的选项 --kubeconfig string 默认值:"/etc/kubernetes/admin.conf" 与集群通信时使用的 kubeconfig 文件。如果未设置该参数,则可以在一组标准位置中搜索现有的 kubeconfig 文件。 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
kubeadm config migrate 概要 此命令允许您在 CLI 工具中将本地旧版本的配置对象转换为最新支持的版本,而无需变更集群中的任何内容。在此版本的 kubeadm 中,支持以下 API 版本:
因此,无论您在此处传递 --old-config 参数的版本是什么,当写入到 stdout 或 --new-config (如果已指定)时,
都会读取、反序列化、默认、转换、验证和重新序列化 API 对象。
换句话说,如果您将此文件传递给 "kubeadm init",则该命令的输出就是 kubeadm 实际上在内部读取的内容。
kubeadm config migrate [flags]
选项 -h, --help migrate 操作的帮助信息 --new-config string 使用新的 API 版本生成的 kubeadm 配置文件的路径。这个路径是可选的。如果没有指定,输出将被写到 stdout。 --old-config string 使用旧 API 版本且应转换的 kubeadm 配置文件的路径。此参数是必需的。
从父命令继承的选项 --kubeconfig string 默认值:"/etc/kubernetes/admin.conf" 用于和集群通信的 kubeconfig 文件。如果未设置,那么 kubeadm 将会搜索一个已经存在于标准路径的 kubeconfig 文件。 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
kubeadm config images list 概要 打印 kubeadm 要使用的镜像列表。配置文件用于自定义任何镜像或镜像存储库。
kubeadm config images list [flags]
选项 --allow-missing-template-keys 默认值:true 如果设置为 true,则在模板中缺少字段或哈希表的键时忽略模板中的任何错误。
仅适用于 golang 和 jsonpath 输出格式。 -o, --experimental-output string 默认值:"text" 输出格式:text|json|yaml|go-template|go-template-file|template|templatefile|jsonpath|jsonpath-as-json|jsonpath-file 其中之一 --config string kubeadm 配置文件的路径。 --feature-gates string 一组键值对(key=value),用于描述各种特征。选项是: Auditing=true|false (ALPHA - 默认=false) CoreDNS=true|false (默认=true) DynamicKubeletConfig=true|false (BETA - 默认=false) -h, --help list 操作的帮助命令 --image-repository string 默认值:"k8s.gcr.io" 选择要从中拉取控制平面镜像的容器仓库 --kubernetes-version string 默认值:"stable-1" 为控制平面选择一个特定的 Kubernetes 版本
从父命令继承的选项 --kubeconfig string 默认值:"/etc/kubernetes/admin.conf" 用于和集群通信的 kubeconfig 文件。如果它没有被设置,那么 kubeadm 将会搜索一个已经存在于标准路径的 kubeconfig 文件。 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
kubeadm config images pull 概要 拉取 kubeadm 使用的镜像。
kubeadm config images pull [flags]
选项 --config string kubeadm 配置文件的路径。 --cri-socket string 要连接的 CRI 套接字的路径。如果为空,则 kubeadm 将尝试自动检测此值;仅当安装了多个 CRI 或具有非标准 CRI 插槽时,才使用此选项。 --feature-gates string 一系列键值对(key=value),用于描述各种特征。可选项是: IPv6DualStack=true|false (ALPHA - 默认值=false) -h, --help pull 操作的帮助命令 --image-repository string 默认值:"k8s.gcr.io" 选择用于拉取控制平面镜像的容器仓库 --kubernetes-version string 默认值:"stable-1" 为控制平面选择一个特定的 Kubernetes 版本。
从父命令继承的选项 --kubeconfig string 默认值:"/etc/kubernetes/admin.conf" 用于和集群通信的 kubeconfig 文件。如果它没有被设置,那么 kubeadm 将会搜索一个已经存在于标准路径的 kubeconfig 文件。 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
接下来 6.7.1.6 - kubeadm reset 该命令尽力还原由 kubeadm init 或 kubeadm join 所做的更改。
概要 尽最大努力还原通过 'kubeadm init' 或者 'kubeadm join' 操作对主机所做的更改
"reset" 命令执行以下阶段:
preflight Run reset pre-flight checks
update-cluster-status Remove this node from the ClusterStatus object.
remove-etcd-member Remove a local etcd member.
cleanup-node Run cleanup node.
kubeadm reset [flags]
选项 --cert-dir string 默认值:"/etc/kubernetes/pki" 存储证书的目录路径。如果已指定,则需要清空此目录。 --cri-socket string 要连接的 CRI 套接字的路径。如果为空,则 kubeadm 将尝试自动检测此值;仅当安装了多个CRI 或具有非标准 CRI 插槽时,才使用此选项。 -f, --force 在不提示确认的情况下重置节点。 -h, --help reset 操作的帮助命令 --ignore-preflight-errors stringSlice 错误将显示为警告的检查列表;例如:'IsPrivilegedUser,Swap'。取值为 'all' 时将忽略检查中的所有错误。 --kubeconfig string 默认值:"/etc/kubernetes/admin.conf" 与集群通信时使用的 kubeconfig 文件。如果未设置该标志,则可以在一组标准位置中搜索现有的 kubeconfig 文件。 --skip-phases stringSlice 要跳过的阶段列表
从父命令继承的选项 --rootfs string [实验] 指向 '真实' 宿主机根文件系统的路径。
Reset 工作流程 kubeadm reset 负责从使用 kubeadm init 或 kubeadm join 命令创建的文件中清除节点本地文件系统。对于控制平面节点,reset 还从 etcd 集群中删除该节点的本地 etcd 堆成员,还从 kubeadm ClusterStatus 对象中删除该节点的信息。
ClusterStatus 是一个 kubeadm 管理的 Kubernetes API 对象,该对象包含 kube-apiserver 端点列表。
kubeadm reset phase 可用于执行上述工作流程的各个阶段。
要跳过阶段列表,你可以使用 --skip-phases 参数,该参数的工作方式类似于 kubeadm join 和 kubeadm init 阶段运行器。
外部 etcd 清理 如果使用了外部 etcd,kubeadm reset 将不会删除任何 etcd 中的数据。这意味着,如果再次使用相同的 etcd 端点运行 kubeadm init,你将看到先前集群的状态。
要清理 etcd 中的数据,建议你使用 etcdctl 这样的客户端,例如:
更多详情请参考 etcd 文档 。
接下来 6.7.1.7 - kubeadm token 如使用引导令牌进行身份验证 所描述的,引导令牌用于在即将加入集群的节点和主节点间建立双向认证。
kubeadm init 创建了一个有效期为 24 小时的令牌,下面的命令允许你管理令牌,也可以创建和管理新的令牌。
kubeadm token create 概要 这个命令将为你创建一个引导令牌。
您可以设置此令牌的用途,"有效时间" 和可选的人性化的描述。
这里的 [token] 是指将要生成的实际令牌。
该令牌应该是一个通过安全机制生成的随机令牌,形式为 "[a-z0-9]{6}.[a-z0-9]{16}"。
如果没有给出 [token],kubeadm 将生成一个随机令牌。
kubeadm token create [token]
选项 --config string kubeadm 配置文件的路径。 --description string 针对令牌用途的人性化的描述。 --groups stringSlice 默认值:[system:bootstrappers:kubeadm:default-node-token] 此令牌用于身份验证时将进行身份验证的其他组。必须匹配 "\\Asystem:bootstrappers:[a-z0-9:-]{0,255}[a-z0-9]\\z" -h, --help create 操作的帮助命令 --print-join-command 不仅仅打印令牌,而是打印使用令牌加入集群所需的完整 'kubeadm join' 参数。 --ttl duration 默认值:24h0m0s 令牌有效时间,超过该时间令牌被自动删除。(例如: 1s, 2m, 3h)。如果设置为 '0',令牌将永远不过期。 --usages stringSlice 默认值:[signing,authentication] 描述可以使用此令牌的方式。你可以多次使用 `--usages` 或者提供一个以逗号分隔的选项列表。合法选项有: [signing,authentication]
从父命令继承的选项 --dry-run 是否启用 `dry-run` 运行模式 --kubeconfig string 默认值:"/etc/kubernetes/admin.conf" 用于和集群通信的 KubeConfig 文件。如果它没有被设置,那么 kubeadm 将会搜索一个已经存在于标准路径的 KubeConfig 文件。 --rootfs string [实验] 指向 '真实' 宿主机根文件系统的路径。
kubeadm token delete 概要 这个命令将为你删除指定的引导令牌列表。
[token-value] 是要删除的 "[a-z0-9]{6}.[a-z0-9]{16}" 形式的完整令牌或者是 "[a-z0-9]{6}" 形式的的令牌 ID。
kubeadm token delete [token-value] ...
选项 从父命令继承的选项 --dry-run 是否启用 `dry-run` 运行模式 --kubeconfig string 默认值:"/etc/kubernetes/admin.conf" 用于和集群通信的 KubeConfig 文件。如果它没有被设置,那么 kubeadm 将会搜索一个已经存在于标准路径的 KubeConfig 文件。 --rootfs string [实验] 指向 '真实' 宿主机根文件系统的路径。
kubeadm token generate 概要 此命令将打印一个随机生成的可以被 "init" 和 "join" 命令使用的引导令牌。
您不必使用此命令来生成令牌。你可以自己设定,只要格式符合 "[a-z0-9]{6}.[a-z0-9]{16}"。这个命令提供是为了方便生成规定格式的令牌。
您也可以使用 "kubeadm init" 并且不指定令牌,该命令会生成一个令牌并打印出来。
kubeadm token generate [flags]
选项 -h, --help generate 操作的帮助命令
从父命令继承的选项 --dry-run 是否启用 `dry-run` 运行模式 --kubeconfig string 默认值:"/etc/kubernetes/admin.conf" 用于和集群通信的 KubeConfig 文件。如果它没有被设置,那么 kubeadm 将会搜索一个已经存在于标准路径的 KubeConfig 文件。 --rootfs string [实验] 指向 '真实' 宿主机根文件系统的路径。
kubeadm token list 概要 此命令将为您列出所有的引导令牌。
kubeadm token list [flags]
选项 --allow-missing-template-keys 默认值:true 如果设置为 true,则在模板中缺少字段或哈希表的键时忽略模板中的任何错误。
仅适用于 golang 和 jsonpath 输出格式。 -o, --experimental-output string 默认值:"text" 输出格式:text|json|yaml|go-template|go-template-file|template|templatefile|jsonpath|jsonpath-as-json|jsonpath-file 其中之一 -h, --help list 操作的帮助命令
从父命令继承的选项 --dry-run 是否启用 `dry-run` 模式 --kubeconfig string 默认值:"/etc/kubernetes/admin.conf" 用于和集群通信的 kubeconfig 文件。如果它没有被设置,那么 kubeadm 将会搜索一个已经存在于标准路径的 kubeconfig 文件。 --rootfs string [实验] 指向 '真实' 宿主机根文件系统的路径。
接下来 6.7.1.8 - kubeadm version 此命令用来输出 kubeadm 的版本。
概要 打印 kubeadm 的版本
kubeadm version [flags]
选项 -h, --help version 操作的帮助命令 -o, --output string 输出格式;可用的选项有 'yaml', 'json' 和 'short'
从父命令继承的选项 --rootfs string [实验] 指向 '真实' 宿主机根文件系统的路径。
6.7.1.9 - kubeadm alpha 注意: kubeadm alpha 提供了一组可用于收集社区反馈的预览性质功能。
请试用这些功能并给我们提供反馈!
kubeadm alpha kubeconfig user 使用子命令 user 为其他用户创建 kubeconfig 文件。
概要 kubeconfig 文件应用程序。
Alpha 免责声明:此命令当前为 alpha 功能。
选项 -h, --help kubeconfig 操作的帮助命令
从父命令继承的选项 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
概要 为其他用户输出 kubeconfig 文件。
Alpha 免责声明:此命令当前为 Alpha 功能。
kubeadm alpha kubeconfig user [flags]
示例 # 使用名为 bar 的 kubeadm 配置文件为名为 foo 的另一用户输出 kubeconfig 文件
kubeadm alpha kubeconfig user --client-name=foo --config=bar
选项 --client-name string 用户名。如果生成客户端证书,则用作其 CN。 --config string 指向 kubeadm 配置文件的路径 -h, --help user 操作的帮助命令 --org stringSlice 客户端证书的组织。如果创建客户端证书,此值将用作其 O 字段值。 --token string 应该用此 kubeconfig 的身份验证机制的令牌,而不是客户端证书
从父命令继承的选项 --rootfs string [实验] 指向 '真实' 宿主机的根目录。
kubeadm alpha kubelet config 使用以下命令启用 DynamicKubeletConfiguration 功能。
概要 此命令并非设计用来单独运行。请参阅可用子命令列表。
选项 -h, --help kubelet 操作的帮助命令
从父命令继承的选项 --rootfs string [实验] 指向 '真实' 宿主机的根目录。
概要 针对集群中的 kubelet-config-1.X ConfigMap 启用或更新节点的动态 kubelet 配置,其中 X 是所需 kubelet 版本的次要版本。
警告:此功能仍处于试验阶段,默认情况下处于禁用状态。仅当知道自己在做什么时才启用它,因为在此阶段它可能会产生令人惊讶的副作用。
Alpha 免责声明:此命令当前为 Alpha 功能。
kubeadm alpha kubelet config enable-dynamic [flags]
示例 # 为节点启用动态 kubelet 配置。
kubeadm alpha phase kubelet enable-dynamic-config --node-name node-1 --kubelet-version 1.16.0
WARNING: This feature is still experimental, and disabled by default. Enable only if you know what you are doing, as it
may have surprising side-effects at this stage.
选项 -h, --help enable-dynamic 操作的帮助命令 --kubeconfig string 默认值: "/etc/kubernetes/admin.conf" 与集群通信时使用的 kubeconfig 文件。如果未设置该标志,则可以在一组标准位置中搜索现有的 kubeconfig 文件。 --kubelet-version string kubelet 所需版本 --node-name string 应该启用动态 kubelet 配置节点的名称
从父命令继承的选项 --rootfs string [实验] 指向 '真实' 宿主机的根目录。
kubeadm alpha selfhosting pivot 子命令 pivot 可用于将 Pod 托管的静态控制平面转换为自托管的控制平面。
有关 pivot 更多信息,请参见
文档 。
概要 此命令并非设计用来单独运行。请参阅可用子命令列表。
选项 -h, --help selfhosting 操作的帮助命令
从父命令继承的选项 --rootfs string [实验] 指向 '真实' 宿主机的根目录。
概要 将用于控制平面组件的静态 Pod 文件转换为通过 Kubernetes API 配置的自托管 DaemonSet。
有关自托管的限制,请参阅相关文档。
Alpha 免责声明:此命令当前为 alpha 功能。
kubeadm alpha selfhosting pivot [flags]
示例 # 将静态 Pod 托管的控制平面转换为自托管的控制平面。
kubeadm alpha phase self-hosting convert-from-staticpods
选项 --cert-dir string 默认值:"/etc/kubernetes/pki" 证书存储的路径 --config string kubeadm 配置文件的路径。 -f, --force 在不提示确认的情况下转换集群 -h, --help pivot 操作的帮助命令 --kubeconfig string 默认值:"/etc/kubernetes/admin.conf" 与集群通信时使用的 kubeconfig 文件。如果未设置该参数,则可以在一组标准位置中搜索现有的 kubeconfig 文件。 -s, --store-certs-in-secrets 启用 secret 存储证书
从父命令继承的选项 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
接下来 6.7.1.10 - kubeadm certs kubeadm certs 提供管理证书的工具。关于如何使用这些命令的细节,可参见
使用 kubeadm 管理证书 。
kubeadm certs 用来操作 Kubernetes 证书的一组命令。
概要 与处理 kubernetes 证书相关的命令
选项 继承于父命令的选项 --rootfs string [实验] 到'真实'主机根文件系统的路径。
kubeadm certs renew 你可以使用 all 子命令来续订所有 Kubernetes 证书,也可以选择性地续订部分证书。
更多的相关细节,可参见
手动续订证书 。
概要 此命令并非设计用来单独运行。请参阅可用子命令列表。
kubeadm certs renew [flags]
选项 从父命令继承的选项 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
概要 续订运行控制平面所需的所有已知证书。续订是无条件进行的,与到期日期无关。续订也可以单独运行以进行更多控制。
kubeadm certs renew all [flags]
选项 --cert-dir string 默认值:"/etc/kubernetes/pki" 存储证书的路径。 --config string kubeadm 配置文件的路径。 --csr-dir string 输出 CSR 和私钥的路径 --csr-only 创建 CSR 而不是生成证书 -h, --help all 操作的帮助命令 --kubeconfig string 默认值:"/etc/kubernetes/admin.conf" 与集群通信时使用的 kubeconfig 文件。
如果未设置该参数,则可以在一组标准位置中搜索现有的 kubeconfig 文件。 --use-api 使用 Kubernetes 证书 API 续订证书
从父命令继承的选项 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
概要 续订 kubeconfig 文件中嵌入的证书,供管理员 和 kubeadm 自身使用。
无论证书的到期日期如何,续订都是无条件进行的;SAN 等额外属性将基于现有文件/证书,因此无需重新提供它们。
默认情况下,续订会尝试使用由 kubeadm 管理的本地 PKI 中的证书机构;作为替代方案,
也可以使用 K8s 证书 API 进行证书续订,或者(作为最后一种选择)生成 CSR 请求。
续订后,为了使更改生效,需要重新启动控制平面组件,并最终重新分发更新的证书,以防证书文件在其他地方使用。
kubeadm certs renew admin.conf [flags]
选项 --cert-dir string 默认值:"/etc/kubernetes/pki" 保存证书的路径。 --config string kubeadm 配置文件的路径。 --csr-dir string CSR 和私钥的输出路径 --csr-only 创建 CSR 而不是生成证书 -h, --help admin.conf 子操作的帮助命令 --kubeconfig string Default: "/etc/kubernetes/admin.conf" 与集群通信时使用的 kubeconfig 文件。
如果未设置该参数,则可以在一组标准位置中搜索现有的 kubeconfig 文件。 --use-api 使用 Kubernetes 证书 API 续订证书
从父命令继承的选项 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
概要 续订 apiserver 用于访问 etcd 的证书。
无论证书的到期日期如何,续订都会无条件地进行;SAN 等额外属性将基于现有文件/证书,因此无需重新提供它们。
默认情况下,续订尝试使用在 kubeadm 所管理的本地 PKI 中的证书颁发机构;作为替代方案,
可以使用 K8s 证书 API 进行证书更新,或者作为最后一个选择来生成 CSR 请求。
续订后,为了使更改生效,需要重新启动控制平面组件,并最终重新分发更新的证书,以防文件在其他地方使用。
kubeadm certs renew apiserver-etcd-client [flags]
选项 --cert-dir string 默认值:"/etc/kubernetes/pki" 存储证书的路径。 --config string kubeadm 配置文件的路径。 --csr-dir string 输出 CSR 和私钥的路径 --csr-only 创建 CSR 而不是生成证书 -h, --help apiserver-etcd-client 操作的帮助命令 --kubeconfig string 默认值:"/etc/kubernetes/admin.conf" 与集群通信时使用的 kubeconfig 文件。
如果未设置该参数,则可以在一组标准位置中搜索现有的 kubeconfig 文件。 --use-api 使用 Kubernetes 证书 API 续订证书
从父命令继承的选项 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
概要 续订 apiserver 用于连接 kubelet 的证书。
无论证书的到期日期如何,续订都会无条件地进行;SAN 等额外属性将基于现有文件/证书,因此无需重新提供它们。
默认情况下,续订尝试使用位于 kubeadm 所管理的本地 PKI 中的证书颁发机构;作为替代方案,
也可能调用 K8s 证书 API 进行证书更新;亦或者,作为最后一个选择,生成 CSR 请求。
续订后,为了使更改生效,需要重新启动控制平面组件,并最终重新分发更新的证书,以防文件在其他地方使用。
kubeadm certs renew apiserver-kubelet-client [flags]
选项 --cert-dir string 默认值:"/etc/kubernetes/pki" 存储证书的路径。 --config string kubeadm 配置文件的路径。 --csr-dir string 输出 CSR 和私钥的路径 --csr-only 创建 CSR 而不是生成证书 -h, --help apiserver-kubelet-client 操作的帮助命令 --kubeconfig string 默认值:"/etc/kubernetes/admin.conf" 与集群通信时使用的 kubeconfig 文件。
如果未设置该参数,则可以在一组标准位置中搜索现有的 kubeconfig 文件。 --use-api 使用 Kubernetes 证书 API 续订证书
从父命令继承的选项 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
概要 续订用于提供 Kubernetes API 的证书。
无论证书的到期日期如何,续订都会无条件地进行;SAN 等额外属性将基于现有文件/证书,因此无需重新提供它们。
默认情况下,续订尝试在 kubeadm 管理的本地 PKI 中使用证书颁发机构;作为替代方案,
可以使用 K8s 证书 API 进行证书更新,或者作为最后一个选择来生成 CSR 请求。
续订后,为了使更改生效,需要重新启动控制平面组件,并最终重新分发更新的证书,以防文件在其他地方使用。
kubeadm certs renew apiserver [flags]
选项 --cert-dir string 默认值:"/etc/kubernetes/pki" 保存证书的路径。 --config string kubeadm 配置文件的路径。 --csr-dir string CSR 和私钥的输出路径 --csr-only 创建 CSR 而不是生成证书 -h, --help apiserver 子操作的帮助命令 --kubeconfig string 默认值:"/etc/kubernetes/admin.conf" 与集群通信时使用的 kubeconfig 文件。
如果未设置该参数,则可以在一组标准位置中搜索现有的 kubeconfig 文件。 --use-api 使用 Kubernetes 证书 API 续订证书
从父命令继承的选项 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
概要 续订 kubeconfig 文件中嵌入的证书,以供控制器管理器(Controller Manager)使用。
续订无条件地进行,与证书的到期日期无关;SAN 等额外属性将基于现有的文件/证书,因此无需重新提供它们。
默认情况下,续订会尝试使用 kubeadm 管理的本地 PKI 中的证书颁发机构;作为替代方案,
可以使用 K8s 证书 API 进行证书续订;亦或者,作为最后一种选择,生成 CSR 请求。
续订后,为了使更改生效,需要重新启动控制平面组件,并最终重新分发更新的证书,以防文件在其他地方使用。
kubeadm alpha renew controller-manager.conf [flags]
选项 --cert-dir string 默认值:"/etc/kubernetes/pki" 保存证书的路径。 --config string kubeadm 配置文件的路径。 --csr-dir string CSR 和私钥的输出路径 --csr-only 创建 CSR 而不是生成证书 -h, --help controller-manager.conf 操作的帮助命令 --kubeconfig string 默认值:"/etc/kubernetes/admin.conf" 与集群通信时使用的 kubeconfig 文件。
如果未设置该参数,则可以在一组标准位置中搜索现有的 kubeconfig 文件。 --use-api 使用 Kubernetes 证书 API 续订证书
从父命令继承的选项 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
概要 续订存活态探针的证书,用于对 etcd 执行健康检查。
无论证书的到期日期如何,续订都是无条件进行的;SAN 等额外属性将基于现有文件/证书,因此无需重新提供它们。
默认情况下,续订会尝试使用由 kubeadm 管理的本地 PKI 中的证书机构;作为替代方案,
也可以使用 K8s certificate API 进行证书续订,或者(作为最后一种选择)生成 CSR 请求。
续订后,为了使更改生效,需要重新启动控制平面组件,并最终重新分发更新的证书,以防证书文件在其他地方使用。
kubeadm certs renew etcd-healthcheck-client [flags]
选项 --cert-dir string 默认值:"/etc/kubernetes/pki" 保存证书的路径。 --config string kubeadm 配置文件的路径。 --csr-dir string CSR 和私钥的输出路径 --csr-only 创建 CSR 而不是生成证书 -h, --help etcd-healthcheck-client 操作的帮助命令 --kubeconfig string 默认值:"/etc/kubernetes/admin.conf" 与集群通信时使用的 kubeconfig 文件。
如果未设置该参数,则可以在一组标准位置中搜索现有的 kubeconfig 文件。 --use-api 使用 Kubernetes 证书 API 续订证书
从父命令继承的选项 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
概要 续订 etcd 节点间用来相互通信的证书。
无论证书的到期日期如何,续订都是无条件进行的;SAN 等额外属性将基于现有文件/证书,因此无需重新提供它们。
默认情况下,续订会尝试使用由 kubeadm 管理的本地 PKI 中的证书机构;
作为替代方案,也可以使用 K8s certificate API 进行证书续订,或者(作为最后一种选择)生成 CSR 请求。
续订后,为了使更改生效,需要重新启动控制平面组件,并最终重新分发更新的证书,以防证书文件在其他地方使用。
kubeadm certs renew etcd-peer [flags]
选项 --cert-dir string 默认值:"/etc/kubernetes/pki" 保存证书的路径。 --config string kubeadm 配置文件的路径。 --csr-dir string CSR 和私钥的输出路径 --csr-only 创建 CSR 而不是生成证书 -h, --help etcd-peer 操作的帮助命令 --kubeconfig string 默认值:"/etc/kubernetes/admin.conf" 与集群通信时使用的 kubeconfig 文件。
如果未设置该参数,则可以在一组标准位置中搜索现有的 kubeconfig 文件。 --use-api 使用 Kubernetes 证书 API 续订证书
从父命令继承的选项 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
概要 续订用于提供 etcd 服务的证书。
续订无条件地进行,与证书的到期日期无关;SAN 等额外属性将基于现有的文件/证书,因此无需重新提供它们。
默认情况下,续订会尝试在 kubeadm 管理的本地 PKI 中使用证书颁发机构;作为替代方案,
可以使用 K8s 证书 API 进行证书续订,或者作为最后一种选择来生成 CSR 请求。
续订后,为了使更改生效,需要重新启动控制平面组件,并最终重新分发更新的证书,以防文件在其他地方使用。
kubeadm certs renew etcd-server [flags]
选项 --cert-dir string 默认值:"/etc/kubernetes/pki" 保存证书的路径。 --config string kubeadm 配置文件的路径。 --csr-dir string CSR 和私钥的输出路径 --csr-only 创建 CSR 而不是生成证书 -h, --help etcd-server 操作的帮助命令 --kubeconfig string 默认值:"/etc/kubernetes/admin.conf" 与集群通信时使用的 kubeconfig 文件。
如果未设置该参数,则可以在一组标准位置中搜索现有的 kubeconfig 文件。 --use-api 使用 Kubernetes 证书 API 续订证书
从父命令继承的选项 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
概要 为前端代理客户端续订证书。
无论证书的到期日期如何,续订都会无条件地进行;SAN 等额外属性将基于现有文件/证书,因此无需重新提供它们。
默认情况下,续订尝试使用位于 kubeadm 所管理的本地 PKI 中的证书颁发机构;作为替代方案,
也可以使用 K8s 证书 API 进行证书续订;亦或者,作为最后一种方案,生成 CSR 请求。
续订后,为了使更改生效,需要重新启动控制平面组件,并最终重新分发更新的证书,以防文件在其他地方使用。
kubeadm certs renew front-proxy-client [flags]
选项 --cert-dir string 默认值:"/etc/kubernetes/pki" 存储证书的路径。 --config string kubeadm 配置文件的路径。 --csr-dir string 输出 CSR 和私钥的路径 --csr-only 创建 CSR 而不是生成证书 -h, --help front-proxy-client 操作的帮助命令 --kubeconfig string 默认值:"/etc/kubernetes/admin.conf" 与集群通信时使用的 kubeconfig 文件。
如果未设置该参数,则可以在一组标准位置中搜索现有的 kubeconfig 文件。 --use-api 使用 Kubernetes 证书 API 续订证书
从父命令继承的选项 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
概要 续订 kubeconfig 文件中嵌入的证书,以供调度管理器使用。
续订无条件地进行,与证书的到期日期无关;SAN 等额外属性将基于现有的文件/证书,因此无需重新提供它们。
默认情况下,续订会尝试使用在 kubeadm 所管理的本地 PKI 中的证书颁发机构;作为替代方案,
也可以使用 K8s 证书 API 进行证书续订;亦或者,作为最后一种选择,生成 CSR 请求。
续订后,为了使更改生效,需要重新启动控制平面组件,并最终重新分发更新的证书,以防文件在其他地方使用。
kubeadm certs renew scheduler.conf [flags]
选项 --cert-dir string 默认值:"/etc/kubernetes/pki" 保存证书的路径。 --config string kubeadm 配置文件的路径。 --csr-dir string CSR 和私钥的输出路径 --csr-only 创建 CSR 而不是生成证书 -h, --help scheduler.conf 操作的帮助命令 --kubeconfig string 默认值:"/etc/kubernetes/admin.conf" 与集群通信时使用的 kubeconfig 文件。
如果未设置该参数,则可以在一组标准位置中搜索现有的 kubeconfig 文件。 --use-api 使用 Kubernetes 证书 API 续订证书
从父命令继承的选项 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
kubeadm certs certificate-key 此命令可用来生成一个新的控制面证书密钥。密钥可以作为 --certificate-key
标志的取值传递给 kubeadm init
和 kubeadm join
命令,从而在添加新的控制面节点时能够自动完成证书复制。
概要 该命令将打印出可以与 "init" 命令一起使用的安全的随机生成的证书密钥。
你也可以使用 kubeadm init --upload-certs 而无需指定证书密钥;
命令将为你生成并打印一个证书密钥。
kubeadm certs certificate-key [flags]
选项 -h, --help certificate-key 操作的帮助命令
从父命令继承的选项 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
kubeadm certs check-expiration 此命令检查 kubeadm 所管理的本地 PKI 中的证书是否以及何时过期。
更多的相关细节,可参见
检查证书过期 。
概要 检查 kubeadm 管理的本地 PKI 中证书的到期时间。
kubeadm certs check-expiration [flags]
选项 --cert-dir string 默认值: "/etc/kubernetes/pki" 保存证书的路径 --config string kubeadm 配置文件的路径 -h, --help check-expiration 的帮助命令
继承于父命令的选项 --rootfs string [实验] 到'真实'主机根文件系统的路径。
kubeadm certs generate-csr 此命令可用来为所有控制面证书和 kubeconfig 文件生成密钥和 CSR(签名请求)。
用户可以根据自身需要选择 CA 为 CSR 签名。
为运行控制平面所需的所有证书生成密钥和证书签名请求(CSR)。该命令会生成部分 kubeconfig 文件,
其中 "users > user > client-key-data" 字段包含私钥数据,并为每个 kubeconfig
文件创建一个随附的 ".csr" 文件。
此命令设计用于
Kubeadm 外部 CA 模式 。
它生成你可以提交给外部证书颁发机构进行签名的 CSR。
应使用 ".crt" 作为文件扩展名将 PEM 编码的签名证书与密钥文件一起保存。
或者,对于 kubeconfig 文件,PEM 编码的签名证书应使用 base64 编码,
并添加到 "users > user > client-certificate-data" 字段。
kubeadm certs generate-csr [flags]
示例 # 以下命令将为所有控制平面证书和 kubeconfig 文件生成密钥和 CSR :
kubeadm certs generate-csr --kubeconfig-dir /tmp/etc-k8s --cert-dir /tmp/etc-k8s/pki
选项 --cert-dir string 保存证书的路径 --config string kubeadm 配置文件的路径。 -h, --help generate-csr 命令的帮助 --kubeconfig-dir string 默认值:"/etc/kubernetes" 保存 kubeconfig 文件的路径。
继承于父命令的选项 --rootfs string [实验] 到'真实'主机根文件系统的路径。
接下来 6.7.1.11 - kubeadm init phase kubeadm init phase 能确保调用引导过程的原子步骤。因此,如果希望自定义应用,则可以让 kubeadm 做一些工作,然后填补空白。
kubeadm init phase 与 kubeadm init 工作流 一致,后台都使用相同的代码。
kubeadm init phase preflight 使用此命令可以在控制平面节点上执行启动前检查。
概要 运行 kubeadm init 前的启动检查。
kubeadm init phase preflight [flags]
案例 # 使用配置文件对 kubeadm init 进行启动检查。
kubeadm init phase preflight --config kubeadm-config.yml
选项 --config string kubeadm 配置文件的路径。 -h, --help preflight 操作的帮助命令 --ignore-preflight-errors stringSlice 错误将显示为警告的检查列表:例如:'IsPrivilegedUser,Swap'。取值为 'all' 时将忽略检查中的所有错误。
继承于父命令的选项 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
kubeadm init phase kubelet-start 此阶段将检查 kubelet 配置文件和环境文件,然后启动 kubelet。
概要 使用 kubelet 配置文件编写一个文件,并使用特定节点的 kubelet 设置编写一个环境文件,然后(重新)启动 kubelet。
kubeadm init phase kubelet-start [flags]
示例 # 从 InitConfiguration 文件中写入带有 kubelet 参数的动态环境文件。
kubeadm init phase kubelet-start --config config.yaml
选项 --config string kubeadm 配置文件的路径。 --cri-socket string 连接到 CRI 套接字的路径。如果为空,则 kubeadm 将尝试自动检测该值;仅当安装了多个 CRI 或具有非标准 CRI 套接字时,才使用此选项。 -h, --help kubelet-start 操作的帮助命令 --node-name string 指定节点名称。
从父命令继承的选项 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
kubeadm init phase certs 该阶段可用于创建 kubeadm 所需的所有证书。
概要 此命令并非设计用来单独运行。请参阅可用子命令列表。
kubeadm init phase certs [flags]
选项 从父指令中继承的选项 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
概要 生成所有证书
kubeadm init phase certs all [flags]
选项 --apiserver-advertise-address string API 服务器所公布的其正在监听的 IP 地址。如果未设置,将使用默认网络接口。 --apiserver-cert-extra-sans stringSlice 用于 API 服务器服务证书的可选额外替代名称(SAN)。可以同时使用 IP 地址和 DNS 名称。 --cert-dir string 默认值:"/etc/kubernetes/pki" 证书的存储路径。 --config string kubeadm 配置文件的路径。 --control-plane-endpoint string 为控制平面指定一个稳定的 IP 地址或 DNS 名称。 -h, --help all 操作的帮助命令 --kubernetes-version string 默认值:"stable-1" 为控制平面选择特定的 Kubernetes 版本。 --service-cidr string 默认值:"10.96.0.0/12" VIP 服务使用其它的 IP 地址范围。 --service-dns-domain string 默认值:"cluster.local" 服务使用其它的域名,例如:"myorg.internal"。
继承于父命令的选项 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
概要 生成自签名的 Kubernetes CA 以提供其他 Kubernetes 组件的身份,并将其保存到 ca.cert 和 ca.key 文件中。
如果两个文件都已存在,则 kubeadm 将跳过生成步骤,使用现有文件。
Alpha 免责声明:此命令当前为 Alpha 功能。
kubeadm init phase certs ca [flags]
选项 --cert-dir string 默认值:"/etc/kubernetes/pki" 证书的存储路径。 --config string kubeadm 配置文件的路径。 -h, --help ca 操作的帮助命令 --kubernetes-version string 默认值:"stable-1" 为控制平面选择特定的 Kubernetes 版本。
继承于父命令的选项 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
概要 生成用于服务 Kubernetes API 的证书,并将其保存到 apiserver.cert 和 apiserver.key 文件中。
默认 SAN 是 kubernetes、kubernetes.default、kubernetes.default.svc、kubernetes.default.svc.cluster.local、10.96.0.1、127.0.0.1。
如果两个文件都已存在,则 kubeadm 将跳过生成步骤,使用现有文件。
Alpha 免责声明:此命令当前为 Alpha 功能。
kubeadm init phase certs apiserver [flags]
选项 --apiserver-advertise-address string API 服务器所公布的其正在监听的 IP 地址。如果未设置,则使用默认的网络接口。 --apiserver-cert-extra-sans stringSlice 用于 API Server 服务证书的可选附加主体备用名称(SAN)。可以是 IP 地址和 DNS 名称。 --cert-dir string 默认值:"/etc/kubernetes/pki" 证书的存储路径。 --config string kubeadm 配置文件的路径。 --control-plane-endpoint string 为控制平面指定一个稳定的 IP 地址或 DNS 名称。 -h, --help apiserver 操作的帮助命令 --kubernetes-version string 默认值:"stable-1" 为控制平面指定特定的 Kubernetes 版本。 --service-cidr string 默认值:"10.96.0.0/12" 指定服务 VIP 可使用的其他 IP 地址段。 --service-dns-domain string 默认值:"cluster.local" 为服务使用其他域名,例如 "myorg.internal"。
继承于父命令的选项 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
概要 生成供 API 服务器连接 kubelet 的证书,并将其保存到 apiserver-kubelet-client.cert 和 apiserver-kubelet-client.key 文件中。
如果两个文件都已存在,则 kubeadm 将跳过生成步骤,使用现有文件。
Alpha 免责声明:此命令当前为 Alpha 功能。
kubeadm init phase certs apiserver-kubelet-client [flags]
选项 --cert-dir string 默认值:"/etc/kubernetes/pki" 存储证书的路径。 --config string kubeadm 配置文件路径。 -h, --help apiserver-kubelet-client 操作的帮助命令 --kubernetes-version string 默认值:"stable-1" 为控制平面指定特定的 Kubernetes 版本。
继承于父命令的选项 --rootfs string [实验] 指向宿主机上的 '实际' 根文件系统的路径。
概要 生成自签名 CA 来提供前端代理的身份,并将其保存到 front-proxy-ca.cert 和 front-proxy-ca.key 文件中。
如果两个文件都已存在,kubeadm 将跳过生成步骤并将使用现有文件。
Alpha 免责声明:此命令目前是 alpha 阶段。
kubeadm init phase certs front-proxy-ca [flags]
选项 --cert-dir string 默认值:"/etc/kubernetes/pki" 存储证书的路径。 --config string kubeadm 配置文件的路径。 -h, --help front-proxy-ca 操作的帮助命令 --kubernetes-version string 默认值:"stable-1" 为控制平面选择特定的 Kubernetes 版本。
从父命令继承的选项 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
概要 为前端代理客户端生成证书,并将其保存到 front-proxy-client.cert 和 front-proxy-client.key 文件中。
如果两个文件都已存在,kubeadm 将跳过生成步骤并将使用现有文件。
Alpha 免责声明:此命令目前是 alpha 阶段。
kubeadm init phase certs front-proxy-client [flags]
选项 --cert-dir string 默认:"/etc/kubernetes/pki" 存储证书的路径。 --config string kubeadm 配置文件的路径。 -h, --help front-proxy-client 操作的帮助命令 --kubernetes-version string 默认值:"stable-1" 为控制平面选择特定的 Kubernetes 版本。
从父命令继承的选项 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
概要 生成用于为 etcd 设置身份的自签名 CA,并将其保存到 etcd/ca.cert 和 etcd/ca.key 文件中。
如果两个文件都已存在,则 kubeadm 将跳过生成步骤,使用现有文件。
Alpha 免责声明:此命令当前为 Alpha 功能。
kubeadm init phase certs etcd-ca [flags]
选项 --cert-dir string 默认值:"/etc/kubernetes/pki" 证书的存储路径。 --config string kubeadm 配置文件的路径。 -h, --help etcd-ca 操作的帮助命令 --kubernetes-version string 默认值:"stable-1" 为控制平面选择特定的 Kubernetes 版本。
继承于父命令的选项 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
概要 生成用于提供 etcd 服务的证书,并将其保存到 etcd/server.cert 和 etcd/server.key 文件中。
默认 SAN 为 localhost、127.0.0.1、127.0.0.1、:: 1
如果两个文件都已存在,则 kubeadm 将跳过生成步骤,使用现有文件。
Alpha 免责声明:此命令当前为 alpha 功能。
kubeadm init phase certs etcd-server [flags]
选项 --cert-dir string 默认值:"/etc/kubernetes/pki" 保存和存储证书的路径。 --config string kubeadm 配置文件的路径。 -h, --help etcd-server 操作的帮助命令 --kubernetes-version string 默认值:"stable-1" 为控制平面指定特定的 Kubernetes 版本。
继承于父命令的选项 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
概要 生成 etcd 节点相互通信的证书,并将其保存到 etcd/peer.cert 和 etcd/peer.key 文件中。
默认 SAN 为 localhost、127.0.0.1、127.0.0.1、:: 1
如果两个文件都已存在,则 kubeadm 将跳过生成步骤,使用现有文件。
Alpha 免责声明:此命令当前为 alpha 功能。
kubeadm init phase certs etcd-peer [flags]
选项 --cert-dir string 默认值:"/etc/kubernetes/pki" 保存和存储证书的路径。 --config string kubeadm 配置文件的路径。 -h, --help etcd-peer 操作的帮助命令 --kubernetes-version string 默认值:"stable-1" 为控制平面指定特定的 Kubernetes 版本。
继承于父命令的选项 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
概要 生成用于 etcd 健康检查的活跃性探针的证书,并将其保存到 healthcheck-client.cert 和 etcd/healthcheck-client.key 文件中。
如果两个文件都已存在,则 kubeadm 将跳过生成步骤,使用现有文件。
Alpha 免责声明:此命令当前为 alpha 功能。
kubeadm init phase certs etcd-healthcheck-client [flags]
选项 --cert-dir string 默认值:"/etc/kubernetes/pki" 证书存储的路径。 --config string kubeadm 配置文件的路径。 -h, --help etcd-healthcheck-client 操作的帮助命令 --kubernetes-version string 默认值:"stable-1" 为控制平面选择特定的 Kubernetes 版本。
继承于父命令的选项 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
概要 生成 apiserver 用于访问 etcd 的证书,并将其保存到 apiserver-etcd-client.cert 和 apiserver-etcd-client.key 文件中。
如果两个文件都已存在,则 kubeadm 将跳过生成步骤,使用现有文件。
Alpha 免责声明:此命令当前为 Alpha 功能。
kubeadm init phase certs apiserver-etcd-client [flags]
选项 --cert-dir string 默认值:"/etc/kubernetes/pki" 证书的存储路径。 --config string kubeadm 配置文件的路径。 -h, --help apiserver-etcd-client 操作的帮助命令 --kubernetes-version string 默认值:"stable-1" 为控制平面指定特定的 Kubernetes 版本。
继承于父命令的选项 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
概要 生成用于签名 service account 令牌的私钥及其公钥,并将其保存到 sa.key 和 sa.pub 文件中。如果两个文件都已存在,则 kubeadm 会跳过生成步骤,而将使用现有文件。
Alpha 免责声明:此命令当前为 alpha 阶段。
kubeadm init phase certs sa [flags]
选项 --cert-dir string 默认值:"/etc/kubernetes/pki" 保存和存储证书的路径。 -h, --help sa 操作的帮助命令
继承于父命令的选项 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
kubeadm init phase kubeconfig 可以通过调用 all 子命令来创建所有必需的 kubeconfig 文件,或者分别调用它们。
概要 此命令并非设计用来单独运行。请阅读可用子命令列表。
kubeadm init phase kubeconfig [flags]
选项 -h, --help kubeconfig 操作的帮助命令
从父命令继承的选项 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
概要 生成所有 kubeconfig 文件
kubeadm init phase kubeconfig all [flags]
选项 --apiserver-advertise-address string API 服务器所公布的其正在监听的 IP 地址。如果没有设置,将使用默认的网络接口。 --apiserver-bind-port int32 默认值:6443 要绑定到 API 服务器的端口。 --cert-dir string 默认值:"/etc/kubernetes/pki" 保存和存储证书的路径。 --config string kubeadm 配置文件的路径。 --control-plane-endpoint string 为控制平面指定一个稳定的 IP 地址或 DNS 名称。 -h, --help all 操作的帮助命令 --kubeconfig-dir string 默认值:"/etc/kubernetes" kubeconfig 文件的保存路径。 --kubernetes-version string 默认值:"stable-1" 为控制平面指定特定的 Kubernetes 版本。 --node-name string 指定节点名称。
继承于父命令的选项 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
概要 为管理员和 kubeadm 本身生成 kubeconfig 文件,并将其保存到 admin.conf 文件中。
kubeadm init phase kubeconfig admin [flags]
选项 --apiserver-advertise-address string API 服务器所公布的其正在监听的 IP 地址。如果未设置,则使用默认的网络接口。 --apiserver-bind-port int32 默认值:6443 要绑定到 API 服务器的端口。 --cert-dir string 默认值:"/etc/kubernetes/pki" 保存和存储证书的路径。 --config string kubeadm 配置文件的路径。 --control-plane-endpoint string 为控制平面指定一个稳定的 IP 地址或 DNS 名称。 -h, --help admin 操作的帮助命令 --kubeconfig-dir string 默认值:"/etc/kubernetes" kubeconfig 文件的保存路径。 --kubernetes-version string 默认值:"stable-1" 为控制平面指定特定的 Kubernetes 版本。
继承于父命令的选项 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
概要 生成 kubelet 要使用的 kubeconfig 文件,并将其保存到 kubelet.conf 文件。
请注意,该操作目的是仅 应用于引导集群。在控制平面启动之后,应该从 CSR API 请求所有 kubelet 凭据。
kubeadm init phase kubeconfig kubelet [flags]
选项 --apiserver-advertise-address string API 服务器所公布的其正在监听的 IP 地址。如果未设置,则使用默认的网络接口。 --apiserver-bind-port int32 默认值:6443 要绑定到 API 服务器的端口。 --cert-dir string 默认值:"/etc/kubernetes/pki" 保存和存储证书的路径。 --config string kubeadm 配置文件的路径。 --control-plane-endpoint string 为控制平面指定一个稳定的 IP 地址或 DNS 名称。 -h, --help kubelet 操作的帮助命令 --kubeconfig-dir string 默认值:"/etc/kubernetes" kubeconfig 文件的保存路径。 --kubernetes-version string 默认值:"stable-1" 为控制平面选择特定的 Kubernetes 版本。 --node-name string 指定节点的名称。
继承于父命令的选项 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
概要 生成控制器管理器要使用的 kubeconfig 文件,并保存到 controller-manager.conf 文件中。
kubeadm init phase kubeconfig controller-manager [flags]
选项 --apiserver-advertise-address string API 服务器所公布的其正在监听的 IP 地址。如果未设置,则使用默认的网络接口。 --apiserver-bind-port int32 默认值:6443 要绑定到 API 服务器的端口。 --cert-dir string 默认值:"/etc/kubernetes/pki" 保存和存储证书的路径。 --config string kubeadm 配置文件的路径。 --control-plane-endpoint string 为控制平面指定一个稳定的 IP 地址或 DNS 名称。 -h, --help controller-manager 操作的帮助命令 --kubeconfig-dir string 默认值:"/etc/kubernetes" kubeconfig 文件的保存路径。 --kubernetes-version string 默认值:"stable-1" 为控制平面指定特定的 Kubernetes 版本。
继承于父命令的选项 --rootfs 字符串 [实验] 到 '真实' 主机根文件系统的路径。
概要 生成调度器(scheduler)要使用的 kubeconfig 文件,并保存到 scheduler.conf 文件中。
kubeadm init phase kubeconfig scheduler [flags]
选项 --apiserver-advertise-address string API 服务器所公布的其正在监听的 IP 地址。如果未设置,则使用默认的网络接口。 --apiserver-bind-port int32 默认值:6443 要绑定到 API 服务器的端口。 --cert-dir string 默认值:"/etc/kubernetes/pki" 保存和存储证书的路径。 --config string kubeadm 配置文件的路径。 --control-plane-endpoint string 为控制平面指定一个稳定的 IP 地址或 DNS 名称。 -h, --help scheduler 操作的帮助命令 --kubeconfig-dir string 默认值:"/etc/kubernetes" kubeconfig 文件的保存路径。 --kubernetes-version string 默认值:"stable-1" 为控制平面指定特定的 Kubernetes 版本。
继承于父命令的选项 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
kubeadm init phase control-plane 使用此阶段,可以为控制平面组件创建所有必需的静态 Pod 文件。
概要 此命令并非设计用来单独运行。请参阅可用子命令列表。
kubeadm init phase control-plane [flags]
选项 -h, --help control-plane 操作的帮助命令
继承于父命令的选项 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
概要 生成所有的静态 Pod 清单文件
kubeadm init phase control-plane all [flags]
示例 # 为控制平面组件生成静态 Pod 清单文件,其功能等效于 kubeadm init 生成的文件。
kubeadm init phase control-plane all
# 使用从某配置文件中读取的选项为生成静态 Pod 清单文件。
kubeadm init phase control-plane all --config config.yaml
选项 --apiserver-advertise-address string API 服务器所公布的其正在监听的 IP 地址。如果未设置,将使用默认的网络接口。 --apiserver-bind-port int32 默认值:6443 API 服务器要绑定的端口。 --apiserver-extra-args mapStringString 形式为 <flagname>=<value> 的一组额外参数,用来传递给 API 服务器,
或者覆盖其默认配置值 --cert-dir string 默认值:"/etc/kubernetes/pki" 存储证书的路径。 --config string kubeadm 配置文件的路径。 --control-plane-endpoint string 为控制平面选择一个稳定的 IP 地址或者 DNS 名称。 --controller-manager-extra-args mapStringString 一组形式为 <flagname>=<value> 的额外参数,用来传递给控制管理器(Controller Manager)
或覆盖其默认设置值 --experimental-patches string 包含名为 "target[suffix][+patchtype].extension" 的文件的目录。
例如,"kube-apiserver0+merge.yaml" 或者 "etcd.json"。
"patchtype" 可以是 "strategic"、"merge" 或 "json" 之一,分别与 kubectl
所支持的 patch 格式相匹配。默认的 "patchtype" 是 "strategic"。
"extension" 必须是 "json" 或 "yaml"。
"suffix" 是一个可选的字符串,用来确定按字母顺序排序时首先应用哪些 patch。 --feature-gates string 一组用来描述各种特性门控的键值(key=value)对。选项是: IPv6DualStack=true|false (ALPHA - 默认=false) PublicKeysECDSA=true|false (ALPHA - 默认=false) -h, --help all 操作的帮助命令 --image-repository string 默认值:"k8s.gcr.io" 选择用于拉取控制平面镜像的容器仓库 --kubernetes-version string 默认值:"stable-1" 为控制平面选择指定的 Kubernetes 版本。 --pod-network-cidr string 指定 Pod 网络的 IP 地址范围。如果设置了此标志,控制平面将自动地为每个节点分配 CIDR。 --scheduler-extra-args mapStringString 一组形式为 <flagname>=<value> 的额外参数,用来传递给调度器(Scheduler)
或覆盖其默认设置值传递给调度器(scheduler)一组额外的参数或者以 <flagname>=<value> 形式覆盖其默认值。
--service-cidr string 默认值:"10.96.0.0/12" 为服务 VIP 选择 IP 地址范围。
从父指令继承的选项 --rootfs string [实验] 指向 '真实' 宿主机的根文件系统的路径。
概要 生成 kube-apiserver 静态 Pod 清单
kubeadm init phase control-plane apiserver [flags]
选项 --apiserver-advertise-address string API 服务器所公布的其正在监听的 IP 地址。如果未设置,将使用默认网络接口。 --apiserver-bind-port int32 默认值: 6443 要绑定到 API 服务器的端口。 --apiserver-extra-args mapStringString 一组 <flagname>=<value> 形式的额外参数,用来传递给 API 服务器
或者覆盖其默认参数配置 --cert-dir string 默认值:"/etc/kubernetes/pki" 保存和存储证书的路径。 --config string kubeadm 配置文件的路径。 --control-plane-endpoint string 为控制平面指定一个稳定的 IP 地址或 DNS 名称。 包含名为 "target[suffix][+patchtype].extension" 的文件的目录。
例如,"kube-apiserver0+merge.yaml" 或者 "etcd.json"。
"patchtype" 可以是 "strategic"、"merge" 或 "json" 之一,分别与 kubectl
所支持的 patch 格式相匹配。默认的 "patchtype" 是 "strategic"。
"extension" 必须是 "json" 或 "yaml"。
"suffix" 是一个可选的字符串,用来确定按字母顺序排序时首先应用哪些 patch。 --feature-gates string 一组键值对,用于描述各种功能特性的特性门控。选项是: IPv6DualStack=true|false (ALPHA - 默认=false) PublicKeysECDSA=true|false (ALPHA - 默认=false) -h, --help apiserver 操作的帮助命令 --image-repository string 默认值:"k8s.gcr.io" 选择要从中拉取控制平面镜像的容器仓库 --kubernetes-version string 默认值:"stable-1" 为控制平面选择特定的 Kubernetes 版本 --service-cidr string 默认值:"10.96.0.0/12" 指定服务 VIP 使用 IP 地址的其他范围。
继承于父命令的选项 --rootfs string [实验] 到 '真实' 主机根文件系统路径。
概要 生成 kube-controller-manager 静态 Pod 清单
kubeadm init phase control-plane controller-manager [flags]
选项 --cert-dir string 默认值:"/etc/kubernetes/pki" 存储证书的路径。 --config string kubeadm 配置文件的路径。 --controller-manager-extra-args mapStringString 一组 <flagname>=< 形式的额外参数,传递给控制器管理器(Controller Manager)
或者覆盖其默认配置值 包含名为 "target[suffix][+patchtype].extension" 的文件的目录。
例如,"kube-apiserver0+merge.yaml" 或者 "etcd.json"。
"patchtype" 可以是 "strategic"、"merge" 或 "json" 之一,分别与 kubectl
所支持的 patch 格式相匹配。默认的 "patchtype" 是 "strategic"。
"extension" 必须是 "json" 或 "yaml"。
"suffix" 是一个可选的字符串,用来确定按字母顺序排序时首先应用哪些 patch。 -h, --help controller-manager 操作的帮助命令 --image-repository string 默认值:"k8s.gcr.io" 选择要从中拉取控制平面镜像的容器仓库 --kubernetes-version string 默认值:"stable-1" 为控制平面选择特定的 Kubernetes 版本。 --pod-network-cidr string 指定 Pod 网络的 IP 地址范围。如果设置,控制平面将自动为每个节点分配 CIDR。
从父命令继承的选项 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
概要 生成 kube-scheduler 静态 Pod 清单
kubeadm init phase control-plane scheduler [flags]
选项 --cert-dir string 默认值:"/etc/kubernetes/pki" 存储证书的路径。 --config string kubeadm 配置文件的路径。 --experimental-patches string 包含名为 "target[suffix][+patchtype].extension" 的文件的目录。
例如,"kube-apiserver0+merge.yaml" 或者 "etcd.json"。
"patchtype" 可以是 "strategic"、"merge" 或 "json" 之一,分别与 kubectl
所支持的 patch 格式相匹配。默认的 "patchtype" 是 "strategic"。
"extension" 必须是 "json" 或 "yaml"。
"suffix" 是一个可选的字符串,用来确定按字母顺序排序时首先应用哪些 patch。 -h, --help scheduler 操作的帮助命令 --image-repository string 默认值:"k8s.gcr.io" 选择要从中拉取控制平面镜像的容器仓库 --kubernetes-version string 默认值:"stable-1" 为控制平面选择特定的 Kubernetes 版本。 --scheduler-extra-args mapStringString 一组 <flagname>=<value> 形式的额外参数,用来传递给调度器
或者覆盖其默认参数配置
继承于父命令的选项 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
kubeadm init phase etcd 根据静态 Pod 文件,使用以下阶段创建本地 etcd 实例。
概要 此命令并非设计用来单独运行。请参阅可用子命令列表。
kubeadm init phase etcd [flags]
选项 继承于父命令的选项 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
概要 为本地单节点 etcd 实例生成静态 Pod 清单文件
kubeadm init phase etcd local [flags]
示例 # 为 etcd 生成静态 Pod 清单文件,其功能等效于 kubeadm init 生成的文件。
kubeadm init phase etcd local
# 使用从配置文件读取的选项为 etcd 生成静态 Pod 清单文件。
kubeadm init phase etcd local --config config.yaml
选项 --cert-dir string 默认值:"/etc/kubernetes/pki" 存储证书的路径。 --config string kubeadm 配置文件的路径。 --experimental-patches string 包含名为 "target[suffix][+patchtype].extension" 的文件的目录的路径。
例如,"kube-apiserver0+merge.yaml" 或仅仅是 "etcd.json"。
"patchtype" 可以是 "strategic"、"merge" 或 "json" 之一,并且它们与 kubectl 支持的补丁格式匹配。
默认的 "patchtype" 为 "strategic"。 "extension" 必须为 "json" 或 "yaml"。
"suffix" 是一个可选字符串,可用于确定首先按字母顺序应用哪些补丁。 -h, --help local 操作的帮助命令 --image-repository string 默认值:"k8s.gcr.io" 选择要从中拉取控制平面镜像的容器仓库
继承于父命令的选项 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
kubeadm init phase upload-config 可以使用此命令将 kubeadm 配置文件上传到集群。或者使用 kubeadm config 。
概要 此命令并非设计用来单独运行。请参阅可用的子命令列表。
kubeadm init phase upload-config [flags]
选项 -h, --help upload-config 操作的帮助命令
从父命令中继承的选项 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
概要 将所有配置上传到 ConfigMap
kubeadm init phase upload-config all [flags]
选项 --config string kubeadm 配置文件的路径。 -h, --help all 操作的帮助命令 --kubeconfig string 默认值:"/etc/kubernetes/admin.conf" 与集群通信时使用的 kubeconfig 文件。如果未设置该参数,则可以在一组标准位置中搜索现有的 kubeconfig 文件。
从父命令继承的选项 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
概要 将 kubeadm ClusterConfiguration 上传到 kube-system 命名空间中名为 kubeadm-config 的 ConfigMap 中。
这样就可以正确配置系统组件,并在升级时提供无缝的用户体验。
另外,可以使用 kubeadm 配置。
kubeadm init phase upload-config kubeadm [flags]
示例 # 上传集群配置
kubeadm init phase upload-config --config=myConfig.yaml
选项 --config string kubeadm 配置文件的路径。 -h, --help kubeadm 操作的帮助命令 --kubeconfig string 默认值:"/etc/kubernetes/admin.conf" 与集群通信时使用的 kubeconfig 文件。如果未设置该参数,则可以在一组标准位置中搜索现有的 kubeconfig 文件。
从父命令继承的选项 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
概要 将从 kubeadm InitConfiguration 对象提取的 kubelet 配置上传到集群中 kubelet-config-1.X 形式的
ConfigMap,其中 X 是当前(API 服务器)Kubernetes 版本的次要版本。
kubeadm init phase upload-config kubelet [flags]
示例 # 将 kubelet 配置从 kubeadm 配置文件上传到集群中的 ConfigMap。
kubeadm init phase upload-config kubelet --config kubeadm.yaml
选项 --config string 到 kubeadm 配置文件的路径。 -h, --help kubelet 操作的帮助命令 --kubeconfig string 默认值:"/etc/kubernetes/admin.conf" 与集群通信时使用的 kubeconfig 文件。如果未设置该标签,则可以通过一组标准路径来寻找已有的 kubeconfig 文件。
从父命令继承的选项 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
kubeadm init phase upload-certs 使用以下阶段将控制平面证书上传到集群。默认情况下,证书和加密密钥会在两个小时后过期。
概要 此命令并非设计用来单独运行。请参阅可用子命令列表。
kubeadm init phase upload-certs [flags]
选项 --certificate-key string 用于加密 kubeadm-certs Secret 中的控制平面证书的密钥。 --config string kubeadm 配置文件的路径。 -h, --help upload-certs 操作的帮助命令 --kubeconfig string 默认值:"/etc/kubernetes/admin.conf" 用来与集群通信的 kubeconfig 文件。
如果此标志未设置,则可以在一组标准的位置搜索现有的 kubeconfig 文件。 --skip-certificate-key-print 不要打印输出用于加密控制平面证书的密钥。 --upload-certs 将控制平面证书上传到 kubeadm-certs Secret。
从父命令继承的选项 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
kubeadm init phase mark-control-plane 使用以下阶段来给具有 node-role.kubernetes.io/master="" 键值对的节点打标签(label)和记录污点(taint)。
概要 标记 Node 节点为控制平面节点
kubeadm init phase mark-control-plane [flags]
示例 # 将控制平面标签和污点应用于当前节点,其功能等效于 kubeadm init执行的操作。
kubeadm init phase mark-control-plane --config config.yml
# 将控制平面标签和污点应用于特定节点
kubeadm init phase mark-control-plane --node-name myNode
选项 --config string kubeadm 配置文件的路径。 -h, --help mark-control-plane 操作的帮助命令 --node-name string 指定节点名称。
从父命令继承的选项 --rootfs 字符串 [实验] 到 '真实' 主机根文件系统的路径。
kubeadm init phase bootstrap-token 使用以下阶段来配置引导令牌。
概要 启动引导令牌(bootstrap token)用于在即将加入集群的节点和控制平面节点之间建立双向信任。
该命令使启动引导令牌(bootstrap token)所需的所有配置生效,然后创建初始令牌。
kubeadm init phase bootstrap-token [flags]
示例 # 进行所有引导令牌配置,并创建一个初始令牌,功能上与 kubeadm init 生成的令牌等效。
kubeadm init phase bootstrap-token
选项 --config string kubeadm 配置文件的路径。 -h, --help bootstrap-token 操作的帮助命令 --kubeconfig string 默认值:"/etc/kubernetes/admin.conf" 用于和集群通信的 kubeconfig 文件。如果它没有被设置,那么 kubeadm 将会搜索一个已经存在于标准路径的 kubeconfig 文件。 --skip-token-print 跳过打印 'kubeadm init' 生成的默认引导令牌。
继承于父命令的选项 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
kubeadm init phase kubelet-finialize 使用以下阶段在 TLS 引导后更新与 kubelet 相关的设置。
你可以使用 all 子命令来运行所有 kubelet-finalize 阶段。
TLS 引导后更新与 kubelet 相关的设置
kubeadm init phase kubelet-finalize [flags]
示例 # 在 TLS 引导后更新与 kubelet 相关的设置
kubeadm init phase kubelet-finalize all --config
选项 -h, --help kubelet-finalize 操作的帮助命令
继承于父命令的选项 --rootfs string [实验] 到'真实'主机根文件系统的路径。
运行所有 kubelet-finalize 阶段
kubeadm init phase kubelet-finalize all [flags]
示例 # 在 TLS 引导后更新与 kubelet 相关的设置
kubeadm init phase kubelet-finalize all --config
选项 --cert-dir string 默认值: "/etc/kubernetes/pki" 保存和存储证书的路径。 --config string kubeadm 配置文件的路径。 -h, --help all 操作的帮助命令
继承于父命令的选项 --rootfs string [实验] 到'真实'主机根文件系统的路径。
启用 kubelet 客户端证书轮换
kubeadm init phase kubelet-finalize experimental-cert-rotation [flags]
选项 --cert-dir string Default: "/etc/kubernetes/pki" 保存和存储证书的路径。 --config string kubeadm 配置文件的路径。 -h, --help experimental-cert-rotation 操作的帮助命令
继承于父命令的选项 --rootfs string [实验] 到'真实'主机根文件系统的路径。
kubeadm init phase addon 可以使用 all 子命令安装所有可用的插件,或者有选择性地安装它们。
概要 此命令并非设计用来单独运行。请参阅可用子命令列表。
kubeadm init phase addon [flags]
选项 继承于父命令的选项 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
概要 安装所有插件(addon)
kubeadm init phase addon all [flags]
选项 --apiserver-advertise-address string API 服务器所公布的其正在监听的 IP 地址。如果未设置,则将使用默认网络接口。 --apiserver-bind-port int32 默认值:6443 API 服务器绑定的端口。 --config string kubeadm 配置文件的路径。 --control-plane-endpoint string 为控制平面指定一个稳定的 IP 地址或 DNS 名称。 --feature-gates string 一组键值对(key=value),描述了各种特征。选项包括: IPv6DualStack=true|false (ALPHA - 默认值=false) -h, --help --image-repository string 默认值:"k8s.gcr.io" 选择用于拉取控制平面镜像的容器仓库 --kubeconfig string 默认值:"/etc/kubernetes/admin.conf" 与集群通信时使用的 kubeconfig 文件。如果未设置该参数,则可以在一组标准位置中搜索现有的 kubeconfig 文件。 --kubernetes-version string 默认值:"stable-1" 为控制平面选择特定的 Kubernetes 版本。 --pod-network-cidr string 指定 Pod 网络的 IP 地址范围。如果已设置,控制平面将自动为每个节点分配 CIDR。 --service-cidr string 默认值:"10.96.0.0/12" 为服务 VIP 使用 IP 地址的其他范围。 --service-dns-domain string 默认值:"cluster.local" 为服务使用其他域名,例如 "myorg.internal"。
继承于父命令的选项 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
概要 通过 API 服务器安装 CoreDNS 附加组件。请注意,即使 DNS 服务器已部署,在安装 CNI 之前 DNS 服务器不会被调度执行。
kubeadm init phase addon coredns [flags]
选项 --config string kubeadm 配置文件的路径。 --feature-gates string 一组用来描述各种功能特性的键值(key=value)对。选项是: IPv6DualStack=true|false (ALPHA - 默认值=false) -h, --help coredns 操作的帮助命令 --image-repository string 默认值:"k8s.gcr.io" 选择用于拉取控制平面镜像的容器仓库 --kubeconfig string 默认值:"/etc/kubernetes/admin.conf" 与集群通信时使用的 kubeconfig 文件。如果未设置该参数,则可以在一组标准位置中搜索现有的 kubeconfig 文件。 --kubernetes-version string 默认值:"stable-1" 为控制平面选择特定的 Kubernetes 版本。 --service-cidr string 默认值:"10.96.0.0/12" 为服务 VIP 选择 IP 地址范围。 --service-dns-domain string 默认值:"cluster.local" 服务使用其它的域名,例如:"myorg.internal"。
继承于父命令的选项 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
概要 通过 API 服务器安装 kube-proxy 附加组件。
kubeadm init phase addon kube-proxy [flags]
选项 --apiserver-advertise-address string API 服务器所公布的其正在监听的 IP 地址。如果未设置,则将使用默认网络接口。 --apiserver-bind-port int32 默认值: 6443 API 服务器绑定的端口。 --config string kubeadm 配置文件的路径。 --control-plane-endpoint string 为控制平面指定一个稳定的 IP 地址或 DNS 名称。 -h, --help kube-proxy 操作的帮助命令 --image-repository string 默认值:"k8s.gcr.io" 选择用于拉取控制平面镜像的容器仓库 --kubeconfig string 默认值:"/etc/kubernetes/admin.conf" 与集群通信时使用的 kubeconfig 文件。如果未设置该参数,则可以在一组标准位置中搜索现有的 kubeconfig 文件。 --kubernetes-version string 默认值:"stable-1" 为控制平面选择特定的 Kubernetes 版本。 --pod-network-cidr string 指定 Pod 网络的 IP 地址范围。如果已设置,控制平面将自动为每个节点分配 CIDR。
继承于父命令的选项 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
要使用 kube-dns 代替 CoreDNS,必须传递一个配置文件:
# 仅用于安装 DNS 插件
kubeadm init phase addon coredns --config= someconfig.yaml
# 用于创建完整的控制平面节点
kubeadm init --config= someconfig.yaml
# 用于列出或者拉取镜像
kubeadm config images list/pull --config= someconfig.yaml
# 升级
kubeadm upgrade apply --config= someconfig.yaml
该文件必须在 ClusterConfiguration 中包含一个 DNS 字段,以及包含一个插件的类型 - kube-dns(默认值为 CoreDNS)。
apiVersion : kubeadm.k8s.io/v1beta2
kind : ClusterConfiguration
dns :
type : "kube-dns"
有关 v1beta2 配置中每个字段的更多详细信息,可以访问 API 。
接下来 6.7.1.12 - kubeadm join phase kubeadm join phase 使你能够调用 join 过程的基本原子步骤。
因此,如果希望执行自定义操作,可以让 kubeadm 做一些工作,然后由用户来补足剩余操作。
kubeadm join phase 与
kubeadm join 工作流程
一致,后台都使用相同的代码。
kubeadm join phase
概要 使用此命令来调用 join 工作流程的某个阶段
选项 从父命令中继承的选项 --rootfs string [实验] 指向 '真实' 宿主机根文件系统的路径。
kubeadm join phase preflight 使用此命令可以在即将加入集群的节点上执行启动前检查。
概要 运行 kubeadm join 命令添加节点前检查。
kubeadm join phase preflight [api-server-endpoint] [flags]
示例 # 使用配置文件运行 kubeadm join 命令添加节点前检查。
kubeadm join phase preflight --config kubeadm-config.yml
选项 --apiserver-advertise-address string 对于将要托管新的控制平面实例的节点,指定 API 服务器将公布的其正在侦听的 IP 地址。如果未设置,则使用默认网络接口。 --apiserver-bind-port int32 默认值:6443 针对将要托管新的控制平面实例的节点,设置 API 服务器要绑定的端口。 --certificate-key string 使用此密钥可以解密由 `init` 操作上传的证书 secret。 --config string kubeadm 配置文件的路径。 --control-plane 在此节点上创建一个新的控制平面实例 --cri-socket string 提供给 CRI 套接字建立连接的路径。如果为空,则 kubeadm 将尝试自动检测该值;仅当安装了多个 CRI 或具有非标准 CRI 套接字时,才使用此选项。 --discovery-file string 对于基于文件的发现,给出用于加载集群信息的文件或者 URL。 --discovery-token string 对于基于令牌的发现,该令牌用于验证从 API 服务器获取的集群信息。 --discovery-token-ca-cert-hash stringSlice 对于基于令牌的发现,验证根 CA 公钥是否匹配此哈希值(格式:"<type>:<value>")。 --discovery-token-unsafe-skip-ca-verification 对于基于令牌的发现,允许在未关联 --discovery-token-ca-cert-hash 参数的情况下添加节点。 -h, --help preflight 操作的帮助命令 --ignore-preflight-errors stringSlice 错误将显示为警告的检查列表;例如:'IsPrivilegedUser,Swap'。取值为 'all' 时将忽略检查中的所有错误。 --node-name string 指定节点名称。 --tls-bootstrap-token string 指定在加入节点时用于临时通过 Kubernetes 控制平面进行身份验证的令牌。 --token string 如果未提供这些值,则将它们用于 discovery-token 令牌和 tls-bootstrap 令牌。
从父命令继承的选项 --rootfs string [实验] 指向 '真实' 宿主机根文件系统的路径。
kubeadm join phase control-plane-prepare 使用此阶段,你可以准备一个作为控制平面的节点。
概要 准备为控制平面服务的机器
kubeadm join phase control-plane-prepare [flags]
示例 # 准备为控制平面服务的机器
kubeadm join phase control-plane-prepare all
选项 -h, --help control-plane-prepare 操作的帮助命令
从父命令中继承的选项 --rootfs string [实验] 指向 '真实' 宿主机根文件系统的路径。
概要 准备为控制平面服务的机器
kubeadm join phase control-plane-prepare all [api-server-endpoint] [flags]
选项 --apiserver-advertise-address string 如果该节点托管一个新的控制平面实例,则 API 服务器将公布其正在侦听的 IP 地址。如果未设置,则使用默认网络接口。 --apiserver-bind-port int32 默认值:6443 如果该节点托管一个新的控制平面实例,则为 API 服务器要绑定的端口。 --certificate-key string 使用此密钥解密由 init 上传的证书 secrets。 --config string kubeadm 配置文件的路径。 --control-plane 在此节点上创建一个新的控制平面实例 --discovery-file string 对于基于文件的发现,给出用于加载集群信息的文件或者 URL。 --discovery-token string 对于基于令牌的发现,该令牌用于验证从 API 服务器获取的集群信息。 --discovery-token-ca-cert-hash stringSlice 对于基于令牌的发现,请验证根 CA 公钥是否匹配此哈希值(格式:"<type>:<value>")。 --discovery-token-unsafe-skip-ca-verification 对于基于令牌的发现,允许在未关联 --discovery-token-ca-cert-hash 参数的情况下添加节点。 --experimental-patches string 包含名为 "target[suffix][+patchtype].extension" 的文件的目录的路径。
例如,"kube-apiserver0+merge.yaml" 或仅仅是 "etcd.json"。
"patchtype" 可以是 "strategic"、"merge" 或 "json" 之一,并且它们与 kubectl 支持的补丁格式匹配。
默认的 "patchtype" 为 "strategic"。 "extension" 必须为 "json" 或 "yaml"。
"suffix" 是一个可选字符串,可用于确定首先按字母顺序应用哪些补丁。 -h, --help all 操作的帮助命令 --node-name string 指定节点名称。 --tls-bootstrap-token string 指定在加入节点时用于临时通过 Kubernetes 控制平面进行身份验证的令牌。 --token string 如果未提供这些值,则将它们用于 discovery-token 令牌和 tls-bootstrap 令牌。
从父命令继承的选项 --rootfs string [实验] 指向 '真实' 宿主机根文件系统的路径。
概要 [实验]从 kubeadm-certs Secret 下载控制平面节点之间共享的证书
kubeadm join phase control-plane-prepare download-certs [api-server-endpoint] [flags]
选项 --certificate-key string 使用此密钥可以解密由 init 上传的证书 secret。 --config string kubeadm 配置文件的路径。 --control-plane 在此节点上创建一个新的控制平面实例 --discovery-file string 对于基于文件的发现,给出用于加载集群信息的文件或者 URL。 --discovery-token string 对于基于令牌的发现,该令牌用于验证从 API 服务器获取的集群信息。 --discovery-token-ca-cert-hash stringSlice 对于基于令牌的发现,请验证根 CA 公钥是否匹配此哈希值(格式:"<type>:<value>")。 --discovery-token-unsafe-skip-ca-verification 对于基于令牌的发现,允许在未关联 --discovery-token-ca-cert-hash 参数的情况下添加节点。 -h, --help kubeconfig 操作的帮助命令 --tls-bootstrap-token string 指定在加入节点时用于临时通过 Kubernetes 控制平面进行身份验证的令牌。 --token string 如果未提供这些值,则将它们用于 discovery-token 令牌和 tls-bootstrap 令牌。
从父命令中继承的选项 --rootfs string [实验] 指向 '真实' 宿主机根文件系统的路径。
概要 为新的控制平面组件生成证书
kubeadm join phase control-plane-prepare certs [api-server-endpoint] [flags]
选项 --apiserver-advertise-address string 如果该节点托管一个新的控制平面实例,则 API 服务器将公布其正在侦听的 IP 地址。如果未设置,则使用默认网络接口。 --config string kubeadm 配置文件的路径。 --control-plane 在此节点上创建一个新的控制平面实例 --discovery-file string 对于基于文件的发现,给出用于加载集群信息的文件或者 URL。 --discovery-token string 对于基于令牌的发现,该令牌用于验证从 API 服务器获取的集群信息。 --discovery-token-ca-cert-hash stringSlice 对于基于令牌的发现,请验证根 CA 公钥是否匹配此哈希值(格式:"<type>:<value>")。 --discovery-token-unsafe-skip-ca-verification 对于基于令牌的发现,允许在未关联 --discovery-token-ca-cert-hash 参数的情况下添加节点。 -h, --help certs 操作的帮助命令 --node-name string 指定节点名称。 --tls-bootstrap-token string 指定在加入节点时用于临时通过 Kubernetes 控制平面进行身份验证的令牌。 --token string 如果未提供这些值,则将它们用于 discovery-token 令牌和 tls-bootstrap 令牌。
从父命令继承的选项 --rootfs string [实验] 指向 '真实' 宿主机根文件系统的路径。
概要 为新的控制平面组件生成 kubeconfig
kubeadm join phase control-plane-prepare kubeconfig [api-server-endpoint] [flags]
选项 --certificate-key string 使用此密钥可以解密由 init 上传的证书 secret。 --config string kubeadm 配置文件的路径。 --control-plane 在此节点上创建一个新的控制平面实例 --discovery-file string 对于基于文件的发现,给出用于加载集群信息的文件或者 URL。 --discovery-token string 对于基于令牌的发现,该令牌用于验证从 API 服务器获取的集群信息。 --discovery-token-ca-cert-hash stringSlice 对于基于令牌的发现,请验证根 CA 公钥是否匹配此哈希值(格式:"<type>:<value>")。 --discovery-token-unsafe-skip-ca-verification 对于基于令牌的发现,允许在未关联 --discovery-token-ca-cert-hash 参数的情况下添加节点。 -h, --help kubeconfig 操作的帮助命令 --tls-bootstrap-token string 指定在加入节点时用于临时通过 Kubernetes 控制平面进行身份验证的令牌。 --token string 如果未提供这些值,则将它们用于 discovery-token 令牌和 tls-bootstrap 令牌。
从父命令中继承的选项 --rootfs string [实验] 指向 '真实' 宿主机根文件系统的路径。
概要 为新的控制平面组件生成清单(manifest)
kubeadm join phase control-plane-prepare control-plane [flags]
选项 --apiserver-advertise-address string 对于将要托管新的控制平面实例的节点,指定 API 服务器将公布的其正在侦听的 IP 地址。如果未设置,则使用默认网络接口。 --apiserver-bind-port int32 默认值:6443 针对将要托管新的控制平面实例的节点,设置 API 服务器要绑定的端口。 --config string kubeadm 配置文件的路径。 --control-plane 在此节点上创建一个新的控制平面实例 --experimental-patches string 包含名为 "target[suffix][+patchtype].extension" 的文件的目录的路径。
例如,"kube-apiserver0+merge.yaml" 或仅仅是 "etcd.json"。
"patchtype" 可以是 "strategic"、"merge" 或 "json" 之一,并且它们与 kubectl 支持的补丁格式匹配。
默认的 "patchtype" 为 "strategic"。 "extension" 必须为 "json" 或 "yaml"。
"suffix" 是一个可选字符串,可用于确定首先按字母顺序应用哪些补丁。 -h, --help control-plane 操作的帮助命令
从父命令中继承的选项 --rootfs string [实验] 指向 '真实' 宿主机根文件系统的路径。
kubeadm join phase kubelet-start 使用此阶段,你可以配置 kubelet 设置、证书和(重新)启动 kubelet。
概要 生成一个包含 KubeletConfiguration 的文件和一个包含特定于节点的 kubelet 配置的环境文件,然后(重新)启动 kubelet。
kubeadm join phase kubelet-start [api-server-endpoint] [flags]
选项 --config string kubeadm 配置文件的路径。 --cri-socket string 提供给 CRI 套接字建立连接的路径。如果为空,则 kubeadm 将尝试自动检测该值;仅当安装了多个 CRI 或具有非标准 CRI 套接字时,才使用此选项。 --discovery-file string For file-based discovery, a file or URL from which to load cluster information.
对于基于文件的发现,给出用于加载集群信息的文件或者 URL。 --discovery-token string 对于基于令牌的发现,该令牌用于验证从 API 服务器获取的集群信息。 --discovery-token-ca-cert-hash stringSlice 对于基于令牌的发现,验证根 CA 公钥是否匹配此哈希值(格式:"<type>:<value>")。 --discovery-token-unsafe-skip-ca-verification 对于基于令牌的发现,允许在未关联 --discovery-token-ca-cert-hash 参数的情况下添加节点。 -h, --help kubelet-start 操作的帮助命令 --node-name string 指定节点名称。 --tls-bootstrap-token string 指定在加入节点时用于临时通过 Kubernetes 控制平面进行身份验证的令牌。 --token string 如果未提供这些值,则将它们用于 discovery-token 令牌和 tls-bootstrap 令牌。
从父命令继承的选项 --rootfs string [实验] 指向 '真实' 宿主机根文件系统的路径。
kubeadm join phase control-plane-join 使用此阶段,你可以将节点作为控制平面实例加入。
概要 添加作为控制平面实例的机器
kubeadm join phase control-plane-join [flags]
示例 # 将机器作为控制平面实例加入
kubeadm join phase control-plane-join all
选项 -h, --help control-plane-join 操作的帮助命令
从父命令中继承的选项 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
概要 添加作为控制平面实例的机器
kubeadm join phase control-plane-join all [flags]
选项 --apiserver-advertise-address string 如果该节点托管一个新的控制平面实例,则 API 服务器将公布其正在侦听的 IP 地址。如果未设置,则使用默认网络接口。 --config string kubeadm 配置文件的路径。 --experimental-control-plane 在此节点上创建一个新的控制平面实例 -h, --help all 操作的帮助命令 --node-name string 指定节点名称。
从父命令继承的选项 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
概要 添加新的本地 etcd 成员
kubeadm join phase control-plane-join etcd [flags]
选项 --apiserver-advertise-address string 如果该节点托管一个新的控制平面实例,则 API 服务器将公布其正在侦听的 IP 地址。如果未设置,则使用默认网络接口。 --config string kubeadm 配置文件的路径。 --control-plane 在此节点上创建一个新的控制平面实例 --experimental-patches string 包含名为 "target[suffix][+patchtype].extension" 的文件的目录的路径。
例如,"kube-apiserver0+merge.yaml" 或仅仅是 "etcd.json"。
"patchtype" 可以是"strategic"、"merge" 或 "json" 之一,并且它们与 kubectl 支持的补丁格式匹配。
默认的 "patchtype" 为 "strategic"。 "extension" 必须为 "json" 或 "yaml"。
"suffix" 是一个可选字符串,可用于确定首先按字母顺序应用哪些补丁。 -h, --help etcd 操作的帮助命令 --node-name string 指定节点的名称
从父命令中继承的选项 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
概要 将新的控制平面节点注册到 kubeadm-config ConfigMap 维护的 ClusterStatus 中
kubeadm join phase control-plane-join update-status [flags]
选项 --apiserver-advertise-address string 如果该节点托管一个新的控制平面实例,则 API 服务器将公布其正在侦听的 IP 地址。如果未设置,则使用默认网络接口。 --config string kubeadm 配置文件的路径。 --control-plane 在此节点上创建一个新的控制平面实例 -h, --help update-status 操作的帮助命令 --node-name string 指定节点名称。
从父命令中继承的选项 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
概要 将 Node 节点标记为控制平面节点
kubeadm join phase control-plane-join mark-control-plane [flags]
选项 --config string kubeadm 配置文件的路径。 --control-plane 在此节点上创建一个新的控制平面实例 -h, --help mark-control-plane 操作的帮助命令 --node-name string 指定节点的名称
从父命令中继承的选项 --rootfs string [实验] 到 '真实' 主机根文件系统的路径。
接下来 6.7.1.13 - kubeadm reset phase kubeadm reset phase 使你能够调用 reset 过程的基本原子步骤。
因此,如果希望执行自定义操作,可以让 kubeadm 做一些工作,然后由用户来补足剩余操作。
kubeadm reset phase 与
kubeadm reset 工作流程
一致,后台都使用相同的代码。
kubeadm reset phase
概要 使用此命令来调用 reset 工作流程的某个阶段
选项 从父命令继承的选项 --rootfs string [实验] 指向 '真实' 宿主机根文件系统的路径。
kubeadm reset phase preflight 使用此阶段,你可以在要重置的节点上执行启动前检查阶段。
概要 kubeadm reset(重置)前运行启动前检查。
kubeadm reset phase preflight [flags]
选项 -f, --force 在不提示确认的情况下重置节点。 -h, --help preflight 操作的帮助命令 --ignore-preflight-errors stringSlice 错误将显示为警告的检查列表;例如:'IsPrivilegedUser,Swap'。取值为 'all' 时将忽略检查中的所有错误。
从父命令继承的选项 --rootfs string [实验] 指向 '真实' 宿主机根文件系统的路径。
kubeadm reset phase update-cluster-status 使用此阶段,你可以从 ClusterStatus 对象中删除此控制平面节点。
概要 如果该节点是控制平面节点,从 ClusterStatus 对象中删除该节点。
kubeadm reset phase update-cluster-status [flags]
选项 -h, --help update-cluster-status 操作的帮助命令
从父命令继承的选项 --rootfs string [实验] 指向 '真实' 宿主机根文件系统的路径。
kubeadm reset phase remove-etcd-member 使用此阶段,你可以从 etcd 集群中删除此控制平面节点的 etcd 成员。
概要 上传关于当前状态的配置,以便 'kubeadm upgrade' 以后可以知道如何配置升级后的集群。
kubeadm config upload [flags]
选项 从父命令继承的选项 --kubeconfig string 默认值: "/etc/kubernetes/admin.conf" 用于和集群通信的 KubeConfig 文件。如果它没有被设置,那么 kubeadm 将会搜索一个已经存在于标准路径的 KubeConfig 文件。 --rootfs string [实验] 到'真实'主机根文件系统的路径。
kubeadm reset phase cleanup-node 使用此阶段,你可以在此节点上执行清理工作。
概要 执行 cleanup node(清理节点)操作。
kubeadm reset phase cleanup-node [flags]
选项 --cert-dir string 默认值:"/etc/kubernetes/pki" 存储证书的目录路径。如果已指定,则需要清空此目录。 --cri-socket string 要连接的 CRI 套接字的路径。如果为空,则 kubeadm 将尝试自动检测此值;仅当安装了多个CRI 或具有非标准 CRI 插槽时,才使用此选项。 -h, --help cleanup-node 操作的帮助命令
从父命令继承的选项 --rootfs string [实验] 指向 '真实' 宿主机根文件系统的路径。
接下来 6.7.1.14 - kubeadm upgrade phase 在 Kubernetes v1.15.0 版本中,kubeadm 引入了对 kubeadm upgrade node 阶段的初步支持。其他 kubeadm upgrade 子命令如 apply 等阶段将在未来发行版中添加。
kubeadm upgrade node phase 使用此阶段,可以选择执行辅助控制平面或工作节点升级的单独步骤。请注意,kubeadm upgrade apply 命令仍然必须在主控制平面节点上调用。
概要 使用此命令调用 node 工作流的某个阶段
选项 从父命令继承的选项 --rootfs string [实验] 指向 '真实' 宿主机根文件系统的路径。
执行 kubeadm 升级节点的预检。
kubeadm upgrade node phase preflight [flags]
选项 -h, --help preflight 操作的帮助命令 --ignore-preflight-errors stringSlice 错误将显示为警告的检查清单。示例:'IsPrivilegedUser,Swap'。值为'all'表示忽略所有检查的错误。
继承于父命令的选项 --rootfs string [实验] 到'真实'主机根文件系统的路径。
概要 升级部署在此节点上的控制平面实例,如果有的话
kubeadm upgrade node phase control-plane [flags]
选项 --certificate-renewal 更新在升级期间变更的组件使用的证书。 --dry-run 不改变任何状态,只输出将要执行的动作。 --etcd-upgrade 默认值: true 执行 etcd 的升级。 --experimental-patches string 包含名为 "target[suffix][+patchtype].extension" 的文件的目录的路径。
例如,"kube-apiserver0+merge.yaml" 或仅仅是 "etcd.json"。
"patchtype" 可以是 "strategic"、"merge" 或 "json" 之一,并且它们与 kubectl 支持的补丁格式匹配。
默认的 "patchtype" 为 "strategic"。 "extension" 必须为 "json" 或 "yaml"。
"suffix" 是一个可选字符串,可用于确定首先按字母顺序应用哪些补丁。 -h, --help control-plane 的帮助信息 --kubeconfig string 默认值: "/etc/kubernetes/admin.conf" 用于和集群通信的 KubeConfig 文件。如果它没有被设置,那么 kubeadm 将会搜索一个已经存在于标准路径的 KubeConfig 文件。
从父命令继承的选项 --rootfs string [实验] 到'真实'主机根文件系统的路径。
从群集中 "kubelet-config-1.X" 的 ConfigMap 下载 kubelet 配置,其中 X 是kubelet 的次要版本。
kubeadm 使用 --kubelet-version 参数来确定所需的 kubelet 版本。
kubeadm upgrade node phase kubelet-config [flags]
选项 --dry-run 不改变任何状态,只输出将要执行的操作 -h, --help 配置操作的帮助信息 --kubeconfig string 默认值: "/etc/kubernetes/kubelet.conf" 用于和集群通信的 KubeConfig 文件。如果它没有被设置,那么 kubeadm 将会搜索一个已经存在于标准路径的 KubeConfig 文件。 --kubelet-version string 升级后的 kubelet 的*期望*版本。
从父命令继承的选项 --rootfs string [实验] 到'真实'主机根文件系统的路径。
接下来 6.7.1.15 - 实现细节 FEATURE STATE: Kubernetes v1.10 [stable]
kubeadm init 和 kubeadm join 结合在一起提供了良好的用户体验,因为从头开始创建实践最佳而配置最基本的 Kubernetes 集群。
但是,kubeadm 如何 做到这一点可能并不明显。
本文档提供了更多幕后的详细信息,旨在分享有关 Kubernetes 集群最佳实践的知识。
核心设计原则 kubeadm init 和 kubeadm join 设置的集群该是:
安全的 :它应采用最新的最佳实践,例如:实施 RBAC 访问控制 使用节点鉴权机制(Node Authorizer) 在控制平面组件之间使用安全通信 在 API 服务器和 kubelet 之间使用安全通信 锁定 kubelet API 锁定对系统组件(例如 kube-proxy 和 CoreDNS)的 API 的访问 锁定启动引导令牌(Bootstrap Token)可以访问的内容 易用的 :用户只需要运行几个命令即可:kubeadm initexport KUBECONFIG=/etc/kubernetes/admin.confkubectl apply -f <所选网络.yaml>kubeadm join --token <令牌> <端点>:<端口>可扩展的 :不 应偏向任何特定的网络提供商。不涉及配置集群网络应该可以使用配置文件来自定义各种参数 常量以及众所周知的值和路径 为了降低复杂性并简化基于 kubeadm 的高级工具的开发,对于众所周知的路径和文件名,
kubeadm 使用了一组有限的常量值。
Kubernetes 目录 /etc/kubernetes 在应用程序中是一个常量,因为在大多数情况下
它显然是给定的路径,并且是最直观的位置;其他路径常量和文件名有:
/etc/kubernetes/manifests 作为 kubelet 查找静态 Pod 清单的路径。静态 Pod 清单的名称为:etcd.yamlkube-apiserver.yamlkube-controller-manager.yamlkube-scheduler.yaml/etc/kubernetes/ 作为带有控制平面组件身份标识的 kubeconfig 文件的路径。kubeconfig 文件的名称为:kubelet.conf (在 TLS 引导时名称为 bootstrap-kubelet.conf )controller-manager.confscheduler.confadmin.conf 用于集群管理员和 kubeadm 本身证书和密钥文件的名称:ca.crt, ca.key 用于 Kubernetes 证书颁发机构apiserver.crt, apiserver.key 用于 API 服务器证书apiserver-kubelet-client.crt, apiserver-kubelet-client.key
用于 API 服务器安全地连接到 kubelet 的客户端证书sa.pub, sa.key 用于控制器管理器签署 ServiceAccount 时使用的密钥front-proxy-ca.crt, front-proxy-ca.key 用于前端代理证书颁发机构front-proxy-client.crt, front-proxy-client.key 用于前端代理客户端 kubeadm init 工作流程内部设计 kubeadm init 内部工作流程
包含一系列要执行的原子性工作任务,如 kubeadm init 中所述。
kubeadm init phase
命令允许用户分别调用每个任务,并最终提供可重用且可组合的 API 或工具箱,
其他 Kubernetes 引导工具、任何 IT 自动化工具和高级用户都可以使用它来
创建自定义集群。
预检 Kubeadm 在启动 init 之前执行一组预检,目的是验证先决条件并避免常见的集群启动问题。
用户可以使用 --ignore-preflight-errors 选项跳过特定的预检查或全部检查。
[警告] 如果要使用的 Kubernetes 版本(由 --kubernetes-version 标志指定)比 kubeadm CLI
版本至少高一个小版本。 Kubernetes 系统要求:如果在 linux上运行:[错误] 如果内核早于最低要求的版本 [错误] 如果未设置所需的 cgroups 子系统 如果使用 docker:[警告/错误] 如果 Docker 服务不存在、被禁用或未激活。 [错误] 如果 Docker 端点不存在或不起作用 [警告] 如果 docker 版本不在经过验证的 docker 版本列表中 如果使用其他 cri 引擎: [错误] 如果用户不是 root 用户 [错误] 如果机器主机名不是有效的 DNS 子域 [警告] 如果通过网络查找无法访问主机名 [错误] 如果 kubelet 版本低于 kubeadm 支持的最低 kubelet 版本(当前小版本 -1) [错误] 如果 kubelet 版本比所需的控制平面板版本至少高一个小(不支持的版本偏斜) [警告] 如果 kubelet 服务不存在或已被禁用 [警告] 如果 firewalld 处于活动状态 [错误] 如果 API 服务器绑定的端口或 10250/10251/10252 端口已被占用 [错误] 如果 /etc/kubernetes/manifest 文件夹已经存在并且不为空 [错误] 如果 /proc/sys/net/bridge/bridge-nf-call-iptables 文件不存在或不包含 1 [错误] 如果建议地址是 ipv6,并且 /proc/sys/net/bridge/bridge-nf-call-ip6tables 不存在或不包含 1 [错误] 如果启用了交换分区 [错误] 如果命令路径中没有 conntrack、ip、iptables、mount、nsenter 命令 [警告] 如果命令路径中没有 ebtables、ethtool、socat、tc、touch、crictl 命令 [警告] 如果 API 服务器、控制器管理器、调度程序的其他参数标志包含一些无效选项 [警告] 如果与 https://API.AdvertiseAddress:API.BindPort 的连接通过代理 [警告] 如果服务子网的连接通过代理(仅检查第一个地址) [警告] 如果 Pod 子网的连接通过代理(仅检查第一个地址) 如果提供了外部 etcd:[错误] 如果 etcd 版本低于最低要求版本 [错误] 如果指定了 etcd 证书或密钥,但无法找到 如果未提供外部 etcd(因此将安装本地 etcd):[错误] 如果端口 2379 已被占用 [错误] 如果 Etcd.DataDir 文件夹已经存在并且不为空 如果授权模式为 ABAC:[错误] 如果 abac_policy.json 不存在 如果授权方式为 Webhook[错误] 如果 webhook_authz.conf 不存在 请注意:
可以使用 kubeadm init phase preflight
命令单独触发预检。 生成必要的证书 Kubeadm 生成用于不同目的的证书和私钥对:
Kubernetes 集群的自签名证书颁发机构会保存到 ca.crt 文件和 ca.key 私钥文件中
用于 API 服务器的服务证书,使用 ca.crt 作为 CA 生成,并将证书保存到 apiserver.crt
文件中,私钥保存到 apiserver.key 文件中
该证书应包含以下备用名称:
Kubernetes 服务的内部 clusterIP(服务 CIDR 的第一个地址。
例如:如果服务的子网是 10.96.0.0/12,则为 10.96.0.1) Kubernetes DNS 名称,例如:如果 --service-dns-domain 标志值是 cluster.local,
则为 kubernetes.default.svc.cluster.local;
加上默认的 DNS 名称 kubernetes.default.svc、kubernetes.default 和 kubernetes, 节点名称 --apiserver-advertise-address用户指定的其他备用名称 用于 API 服务器安全连接到 kubelet 的客户端证书,使用 ca.crt 作为 CA 生成,
并保存到 apiserver-kubelet-client.crt,私钥保存到 apiserver-kubelet-client.key
文件中。该证书应该在 system:masters 组织中。
用于签名 ServiceAccount 令牌的私钥保存到 sa.key 文件中,公钥保存到 sa.pub 文件中
用于前端代理的证书颁发机构保存到 front-proxy-ca.crt 文件中,私钥保存到
front-proxy-ca.key 文件中
前端代理客户端的客户端证书,使用 front-proxy-ca.crt 作为 CA 生成,并保存到
front-proxy-client.crt 文件中,私钥保存到 front-proxy-client.key 文件中
证书默认情况下存储在 /etc/kubernetes/pki 中,但是该目录可以使用 --cert-dir 标志进行配置。
请注意:
如果证书和私钥对都存在,并且其内容经过评估符合上述规范,将使用现有文件,
并且跳过给定证书的生成阶段。
这意味着用户可以将现有的 CA 复制到 /etc/kubernetes/pki/ca.{crt,key},
kubeadm 将使用这些文件对其余证书进行签名。
请参阅使用自定义证书 。 仅对 CA 来说,如果所有其他证书和 kubeconfig 文件都已就位,则可以只提供 ca.crt 文件,
而不提供 ca.key 文件。
kubeadm 能够识别出这种情况并启用 ExternalCA,这也意味着了控制器管理器中的
csrsigner 控制器将不会启动 如果 kubeadm 在
外部 CA 模式
下运行,所有证书必须由用户提供,因为 kubeadm 无法自行生成它们。 如果在 --dry-run 模式下执行 kubeadm,证书文件将写入一个临时文件夹中 可以使用 kubeadm init phase certs all
命令单独生成证书。 为控制平面组件生成 kubeconfig 文件 Kubeadm 生成具有用于控制平面组件身份标识的 kubeconfig 文件:
供 kubelet 在 TLS 引导期间使用的 kubeconfig 文件 —— /etc/kubernetes/bootstrap-kubelet.conf。
在此文件中,有一个引导令牌或内嵌的客户端证书,向集群表明此节点身份。
此客户端证书应:
根据节点鉴权 模块的要求,属于 system:nodes 组织 具有通用名称(CN):system:node:<小写主机名> 控制器管理器的 kubeconfig 文件 —— /etc/kubernetes/controller-manager.conf;
在此文件中嵌入了一个具有控制器管理器身份标识的客户端证书。
此客户端证书应具有 CN:system:kube-controller-manager,
该 CN 由 RBAC 核心组件角色
默认定义的。
调度器的 kubeconfig 文件 —— /etc/kubernetes/scheduler.conf;
此文件中嵌入了具有调度器身份标识的客户端证书。此客户端证书应具有 CN:system:kube-scheduler,
该 CN 由 RBAC 核心组件角色
默认定义的。
另外,用于 kubeadm 本身和 admin 的 kubeconfig 文件也被生成并保存到
/etc/kubernetes/admin.conf 文件中。
此处的 admin 定义为正在管理集群并希望完全控制集群(root )的实际人员。
内嵌的 admin 客户端证书应是 system:masters 组织的成员,
这一组织名由默认的 RBAC 面向用户的角色绑定
定义。它还应包括一个 CN。kubeadm 使用 kubernetes-admin CN。
请注意:
ca.crt 证书内嵌在所有 kubeconfig 文件中。如果给定的 kubeconfig 文件存在且其内容经过评估符合上述规范,则 kubeadm 将使用现有文件,
并跳过给定 kubeconfig 的生成阶段 如果 kubeadm 以 ExternalCA 模式
运行,则所有必需的 kubeconfig 也必须由用户提供,因为 kubeadm 不能自己生成 如果在 --dry-run 模式下执行 kubeadm,则 kubeconfig 文件将写入一个临时文件夹中 可以使用
kubeadm init phase kubeconfig all
命令分别生成 kubeconfig 文件。 为控制平面组件生成静态 Pod 清单 Kubeadm 将用于控制平面组件的静态 Pod 清单文件写入 /etc/kubernetes/manifests 目录。
Kubelet 启动后会监视这个目录以便创建 Pod。
静态 Pod 清单有一些共同的属性:
所有静态 Pod 都部署在 kube-system 名字空间
所有静态 Pod 都打上 tier:ontrol-plane 和 component:{组件名称} 标签
所有静态 Pod 均使用 system-node-critical 优先级
所有静态 Pod 都设置了 hostNetwork:true,使得控制平面在配置网络之前启动;结果导致:
控制器管理器和调度器用来调用 API 服务器的地址为 127.0.0.1。 如果使用本地 etcd 服务器,则 etcd-servers 地址将设置为 127.0.0.1:2379 同时为控制器管理器和调度器启用了领导者选举
控制器管理器和调度器将引用 kubeconfig 文件及其各自的唯一标识
如将自定义参数传递给控制平面组件
中所述,所有静态 Pod 都会获得用户指定的额外标志
所有静态 Pod 都会获得用户指定的额外卷(主机路径)
请注意:
所有镜像默认从 k8s.gcr.io 拉取。
关于自定义镜像仓库,请参阅
使用自定义镜像 。 如果在 --dry-run 模式下执行 kubeadm,则静态 Pod 文件写入一个临时文件夹中。 可以使用 kubeadm init phase control-plane all
命令分别生成主控组件的静态 Pod 清单。 API 服务器 API 服务器的静态 Pod 清单会受到用户提供的以下参数的影响:
要绑定的 apiserver-advertise-address 和 apiserver-bind-port;
如果未提供,则这些值默认为机器上默认网络接口的 IP 地址和 6443 端口。 service-cluster-ip-range 给 service 使用如果指定了外部 etcd 服务器,则应指定 etcd-servers 地址和相关的 TLS 设置
(etcd-cafile,etcd-certfile,etcd-keyfile);
如果未提供外部 etcd 服务器,则将使用本地 etcd(通过主机网络) 如果指定了云提供商,则配置相应的 --cloud-provider,如果该路径存在,则配置 --cloud-config
(这是实验性的,是 Alpha 版本,将在以后的版本中删除) 无条件设置的其他 API 服务器标志有:
--insecure-port=0 禁止到 API 服务器不安全的连接--enable-bootstrap-token-auth=true 启用 BootstrapTokenAuthenticator 身份验证模块。
更多细节请参见 TLS 引导 。--allow-privileged 设为 true(诸如 kube-proxy 这些组件有此要求)--requestheader-client-ca-file 设为 front-proxy-ca.crt--enable-admission-plugins 设为:--kubelet-preferred-address-types 设为 InternalIP,ExternalIP,Hostname;
这使得在节点的主机名无法解析的环境中,kubectl log 和 API 服务器与 kubelet
的其他通信可以工作
使用在前面步骤中生成的证书的标志:
--client-ca-file 设为 ca.crt--tls-cert-file 设为 apiserver.crt--tls-private-key-file 设为 apiserver.key--kubelet-client-certificate 设为 apiserver-kubelet-client.crt--kubelet-client-key 设为 apiserver-kubelet-client.key--service-account-key-file 设为 sa.pub--requestheader-client-ca-file 设为 front-proxy-ca.crt--proxy-client-cert-file 设为 front-proxy-client.crt--proxy-client-key-file 设为 front-proxy-client.key其他用于保护前端代理(
API 聚合层 )
通信的标志:
--requestheader-username-headers=X-Remote-User--requestheader-group-headers=X-Remote-Group--requestheader-extra-headers-prefix=X-Remote-Extra---requestheader-allowed-names=front-proxy-client控制器管理器 控制器管理器的静态 Pod 清单受用户提供的以下参数的影响:
如果调用 kubeadm 时指定了 --pod-network-cidr 参数,则可以通过以下方式启用
某些 CNI 网络插件所需的子网管理器功能:设置 --allocate-node-cidrs=true 根据给定 CIDR 设置 --cluster-cidr 和 --node-cidr-mask-size 标志 如果指定了云提供商,则指定相应的 --cloud-provider,如果存在这样的配置文件,
则指定 --cloud-config 路径(此为试验性功能,是 Alpha 版本,将在以后的版本中删除)。 其他无条件设置的标志包括:
--controllers 为 TLS 引导程序启用所有默认控制器以及 BootstrapSigner 和
TokenCleaner 控制器。详细信息请参阅
TLS 引导
--use-service-account-credentials 设为 true
使用先前步骤中生成的证书的标志:
---root-ca-file 设为 ca.crt
如果禁用了 External CA 模式,则 --cluster-signing-cert-file 设为 ca.crt,否则设为 "" 如果禁用了 External CA 模式,则 --cluster-signing-key-file 设为 ca.key,否则设为 "" --service-account-private-key-file 设为 sa.key调度器 调度器的静态 Pod 清单不受用户提供的参数的影响。
为本地 etcd 生成静态 Pod 清单 如果用户指定了外部 etcd,则将跳过此步骤,否则 kubeadm 会生成静态 Pod 清单文件,
以创建在 Pod 中运行的具有以下属性的本地 etcd 实例:
在 localhost:2379 上监听并使用 HostNetwork=true 将 hostPath 从 dataDir 挂载到主机的文件系统 用户指定的任何其他标志 请注意:
etcd 镜像默认从 k8s.gcr.io 拉取。有关自定义镜像仓库,请参阅
使用自定义镜像 。 如果 kubeadm 以 --dry-run 模式执行,etcd 静态 Pod 清单将写入一个临时文件夹。 可以使用
'kubeadm init phase etcd local'
命令单独为本地 etcd 生成静态 Pod 清单 可选的动态 Kubelet 配置 要使用这个功能,请执行 kubeadm alpha kubelet config enable-dynamic。
它将 kubelet 的初始化配置写入 /var/lib/kubelet/config/init/kubelet 文件。
初始化配置用于在这个特定节点上启动 kubelet,从而为 kubelet 插件文件提供了
一种替代方法。如以下步骤中所述,这种配置将由 kubelet 基本配置所替代。
请参阅通过配置文件设置 Kubelet 参数
了解更多信息。
请注意:
要使动态 kubelet 配置生效,应在 /etc/systemd/system/kubelet.service.d/10-kubeadm.conf
中指定 --dynamic-config-dir=/var/lib/kubelet/config/dynamic 标志。 通过使用配置文件 --config some-file.yaml 将 KubeletConfiguration 对象传递给
kubeadm init 或 kubeadm join 来更改 kubelet 配置。
可以使用 --- 分隔符将 KubeletConfiguration 对象与其他对象(例如 InitConfiguration)
分开。更多的详细信息,请查看 kubeadm config print-default 命令。 等待控制平面启动 kubeadm 等待(最多 4m0s),直到 localhost:6443/healthz(kube-apiserver 存活)返回 ok。
但是为了检测死锁条件,如果 localhost:10255/healthz(kubelet 存活)或
localhost:10255/healthz/syncloop(kubelet 就绪)未能在 40s 和 60s 内未返回 ok,
则 kubeadm 会快速失败。
kubeadm 依靠 kubelet 拉取控制平面镜像并将其作为静态 Pod 正确运行。
控制平面启动后,kubeadm 将完成以下段落中描述的任务。
(可选)编写基本 kubelet 配置 FEATURE STATE: Kubernetes v1.9 [alpha]
如果带 --feature-gates=DynamicKubeletConfig 参数调用 kubeadm,则 kubeadm:
将 kubelet 基本配置写入 kube-system 名字空间的 kubelet-base-config-v1.9 ConfigMap 中。 创建 RBAC 规则,以授予对所有引导令牌和所有 kubelet 实例对该 ConfigMap 的读取访问权限
(即 system:bootstrappers:kubeadm:default-node-token 组和 system:nodes 组) 通过将 Node.spec.configSource 指向新创建的 ConfigMap,为初始控制平面节点启用动态
kubelet 配置功能。 将 kubeadm ClusterConfiguration 保存在 ConfigMap 中以供以后参考 kubeadm 将传递给 kubeadm init 的配置保存在 kube-system 名字空间下名为
kubeadm-config 的 ConfigMap 中。
这将确保将来执行的 kubeadm 操作(例如 kubeadm upgrade)将能够确定实际/当前集群状态,
并根据该数据做出新的决策。
请注意:
在保存 ClusterConfiguration 之前,从配置中删除令牌等敏感信息。 可以使用
kubeadm init phase upload-config
命令单独上传主控节点配置。 将节点标记为控制平面 一旦控制平面可用,kubeadm 将执行以下操作:
给节点打上 node-role.kubernetes.io/master="" 标签,标记其为控制平面 给节点打上 node-role.kubernetes.io/master:NoSchedule 污点 请注意:
可以使用 kubeadm init phase mark-control-plane
命令单独触发控制平面标记 Kubeadm 使用引导令牌认证
将新节点连接到现有集群;
更多的详细信息,请参见
设计提案 。
kubeadm init 确保为该过程正确配置了所有内容,这包括以下步骤以及设置 API 服务器
和控制器标志,如前几段所述。
请注意:
可以使用
kubeadm init phase bootstrap-token
命令配置节点的 TLS 引导,执行以下段落中描述的所有配置步骤;
或者每个步骤都单独触发。 创建引导令牌 kubeadm init 创建第一个引导令牌,该令牌是自动生成的或由用户提供的 --token
标志的值;如引导令牌规范中记录的那样,
令牌应保存在 kube-system 名字空间下名为 bootstrap-token-<令牌-id>
的 Secret 中。
请注意:
由 kubeadm init 创建的默认令牌将用于在 TLS 引导过程中验证临时用户;
这些用户会成为 system:bootstrappers:kubeadm:default-node-token 组的成员。 令牌的有效期有限,默认为 24 小时(间隔可以通过 -token-ttl 标志进行更改) 可以使用 kubeadm token
命令创建其他令牌,这些令牌还提供其他有用的令牌管理功能 允许加入的节点调用 CSR API Kubeadm 确保 system:bootstrappers:kubeadm:default-node-token 组中的用户
能够访问证书签名 API。
这是通过在上述组与默认 RBAC 角色 system:node-bootstrapper 之间创建名为
kubeadm:kubelet-bootstrap 的 ClusterRoleBinding 来实现的。
为新的引导令牌设置自动批准 Kubeadm 确保 csrapprover 控制器自动批准引导令牌的 CSR 请求。
这是通过在 system:bootstrappers:kubeadm:default-node-token 用户组和
system:certificates.k8s.io:certificatesigningrequests:nodeclient 默认角色之间
创建名为 kubeadm:node-autoapprove-bootstrap 的 ClusterRoleBinding 来实现的。
还应创建 system:certificates.k8s.io:certificatesigningrequests:nodeclient 角色,
授予对 /apis/certificates.k8s.io/certificatesigningrequests/nodeclient
执行 POST 的权限。
通过自动批准设置节点证书轮换 Kubeadm 确保节点启用了证书轮换,csrapprover 控制器将自动批准节点的
新证书的 CSR 请求。
这是通过在 system:nodes 组和
system:certificates.k8s.io:certificatesigningrequests:selfnodeclient
默认角色之间创建名为 kubeadm:node-autoapprove-certificate-rotation 的
ClusterRoleBinding 来实现的。
创建公共 cluster-info ConfigMap 本步骤在 kube-public 名字空间中创建名为 cluster-info 的 ConfigMap。
另外,它创建一个 Role 和一个 RoleBinding,为未经身份验证的用户授予对 ConfigMap
的访问权限(即 RBAC 组 system:unauthenticated 中的用户)。
请注意:
对 cluster-info ConfigMap 的访问 不受 速率限制。
如果你把 API 服务器暴露到外网,这可能是一个问题,也可能不是;
这里最坏的情况是 DoS 攻击,攻击者使用 kube-apiserver 能够处理的所有动态请求
来为 cluster-info ConfigMap 提供服务。 安装插件 Kubeadm 通过 API 服务器安装内部 DNS 服务器和 kube-proxy 插件。
请注意:
此步骤可以调用
'kubeadm init phase addon all'
命令单独执行。 代理 在 kube-system 名字空间中创建一个用于 kube-proxy 的 ServiceAccount;
然后以 DaemonSet 的方式部署 kube-proxy:
主控节点凭据(ca.crt 和 token)来自 ServiceAccount API 服务器节点的位置(URL)来自 ConfigMap kube-proxy 的 ServiceAccount 绑定了 system:node-proxier ClusterRole
中的特权DNS 在 Kubernetes 1.18 版本中,通过 kubeadm 部署 kube-dns 这一操作已经弃用,
将在未来的版本中删除。 CoreDNS 服务的名称为 kube-dns。这样做是为了防止当用户将集群 DNS 从 kube-dns
切换到 CoreDNS 或者反过来时,出现服务中断。--config 方法在
这里
有描述。 在 kube-system 名字空间中创建 CoreDNS/kube-dns 的 ServiceAccount kube-dns 的 ServiceAccount 绑定了 system:kube-dns ClusterRole 中的特权kubeadm join 步骤内部设计 与 kubeadm init 类似,kubeadm join 内部工作流由一系列待执行的原子工作任务组成。
这分为发现(让该节点信任 Kubernetes 的主控节点)和 TLS 引导
(让 Kubernetes 的主控节点信任该节点)。
请参阅使用引导令牌进行身份验证
或相应的设计提案 。
预检 kubeadm 在开始执行之前执行一组预检,目的是验证先决条件,避免常见的集群启动问题。
请注意:
kubeadm join 预检基本上是 kubeadm init 预检的一个子集从 1.9 开始,kubeadm 为 CRI 通用的功能提供了更好的支持;在这种情况下,
Docker 特定的控制参数将跳过或替换为 crictl 中与之相似的控制参数。 从 1.9 开始,kubeadm 支持加入在 Windows 上运行的节点;在这种情况下,
将跳过 Linux 特定的控制参数。 在任何情况下,用户都可以通过 --ignore-preflight-errors 选项跳过
特定的预检(或者进而跳过所有预检)。 发现 cluster-info 主要有两种发现方案。第一种是使用一个共享令牌以及 API 服务器的 IP 地址。
第二种是提供一个文件(它是标准 kubeconfig 文件的子集)。
共享令牌发现 如果带 --discovery-token 参数调用 kubeadm join,则使用了令牌发现功能;
在这种情况下,节点基本上从 kube-public 名字空间中的 cluster-info ConfigMap
中检索集群 CA 证书。
为了防止“中间人”攻击,采取了以下步骤:
首先,通过不安全连接检索 CA 证书(这是可能的,因为 kubeadm init 授予
system:unauthenticated 的用户对 cluster-info 访问权限) 然后 CA 证书通过以下验证步骤:基本验证:使用令牌 ID 而不是 JWT 签名 公钥验证:使用提供的 --discovery-token-ca-cert-hash。这个值来自 kubeadm init 的输出,
或者可以使用标准工具计算(哈希值是按 RFC7469 中主体公钥信息(SPKI)对象的字节计算的)
--discovery-token-ca-cert-hash 标志可以重复多次,以允许多个公钥。 作为附加验证,通过安全连接检索 CA 证书,然后与初始检索的 CA 进行比较 请注意:
通过 --discovery-token-unsafe-skip-ca-verification 标志可以跳过公钥验证;
这削弱了 kubeadm 安全模型,因为其他人可能冒充 Kubernetes 主控节点。 文件/HTTPS 发现 如果带 --discovery-file 参数调用 kubeadm join,则使用文件发现功能;
该文件可以是本地文件或通过 HTTPS URL 下载;对于 HTTPS,主机安装的 CA 包
用于验证连接。
通过文件发现,集群 CA 证书是文件本身提供;事实上,这个发现文件是一个 kubeconfig 文件,
只设置了 server 和 certificate-authority-data 属性,
如 kubeadm join
参考文档中所述,当与集群建立连接时,kubeadm 尝试访问 cluster-info ConfigMap,
如果可用,就使用它。
TLS 引导 知道集群信息后,将写入文件 bootstrap-kubelet.conf,从而允许 kubelet 执行
TLS 引导(相反,在 v1.7 之前 TLS 引导都是由 kubeadm 管理)。
TLS 引导机制使用共享令牌对 Kubernetes 主控节点进行临时身份验证,以便
为本地创建的密钥对提交证书签名请求(CSR)。
该请求会被自动批准,并且该操作保存 ca.crt 文件和 kubelet.conf 文件,用于
kubelet 加入集群,同时删除 bootstrap-kubelet.conf。
请注意:
临时身份验证根据 kubeadm init 过程中保存的令牌进行验证(或者使用 kubeadm token
创建的其他令牌) 临时身份验证解析到 system:bootstrappers:kubeadm:default-node-token 组的一个用户成员,
该成员在 kubeadm init 过程中被授予对 CSR API 的访问权 根据 kubeadm init 过程的配置,自动 CSR 审批由 csrapprover 控制器管理 (可选)编写 init kubelet 配置 FEATURE STATE: Kubernetes v1.9 [alpha]
如果带 --feature-gates=DynamicKubeletConfig 参数调用 kubeadm,则 kubeadm:
使用引导令牌凭证从 kube-system 名字空间中 ConfigMap kubelet-base-config-v1.9
中读取 kubelet 基本配置,
并将其作为 kubelet init 配置文件 /var/lib/kubelet/config/init/kubelet 写入磁盘。 一旦 kubelet 开始使用节点自己的凭据(/etc/kubernetes/kubelet.conf),
就更新当前节点配置,指定该节点或 kubelet 配置来自上述 ConfigMap。 请注意:
要使动态 kubelet 配置生效,应在 /etc/systemd/system/kubelet.service.d/10-kubeadm.conf
中指定 --dynamic-config-dir=/var/lib/kubelet/config/dynamic 标志。
6.8 - kubectl 命令行界面 6.8.1 - kubectl 概述 你可以使用 Kubectl 命令行工具管理 Kubernetes 集群。
kubectl 在 $HOME/.kube 目录中查找一个名为 config 的配置文件。
你可以通过设置 KUBECONFIG 环境变量或设置
--kubeconfig
参数来指定其它 kubeconfig 文件。
本文概述了 kubectl 语法和命令操作描述,并提供了常见的示例。
有关每个命令的详细信息,包括所有受支持的参数和子命令,
请参阅 kubectl 参考文档。
有关安装说明,请参见安装 kubectl 。
语法 使用以下语法 kubectl 从终端窗口运行命令:
kubectl [ command] [ TYPE] [ NAME] [ flags]
其中 command、TYPE、NAME 和 flags 分别是:
flags: 指定可选的参数。例如,可以使用 -s 或 -server 参数指定
Kubernetes API 服务器的地址和端口。注意: 从命令行指定的参数会覆盖默认值和任何相应的环境变量。
如果你需要帮助,只需从终端窗口运行 kubectl help 即可。
操作 下表包含所有 kubectl 操作的简短描述和普通语法:
操作 语法 描述 alphakubectl alpha SUBCOMMAND [flags]列出与 alpha 特性对应的可用命令,这些特性在 Kubernetes 集群中默认情况下是不启用的。 annotatekubectl annotate (-f FILENAME | TYPE NAME | TYPE/NAME) KEY_1=VAL_1 ... KEY_N=VAL_N [--overwrite] [--all] [--resource-version=version] [flags]添加或更新一个或多个资源的注解。 api-resourceskubectl api-resources [flags]列出可用的 API 资源。 api-versionskubectl api-versions [flags]列出可用的 API 版本。 applykubectl apply -f FILENAME [flags]从文件或 stdin 对资源应用配置更改。 attachkubectl attach POD -c CONTAINER [-i] [-t] [flags]附加到正在运行的容器,查看输出流或与容器(stdin)交互。 authkubectl auth [flags] [options]检查授权。 autoscalekubectl autoscale (-f FILENAME | TYPE NAME | TYPE/NAME) [--min=MINPODS] --max=MAXPODS [--cpu-percent=CPU] [flags]自动伸缩由副本控制器管理的一组 pod。 certificatekubectl certificate SUBCOMMAND [options]修改证书资源。 cluster-infokubectl cluster-info [flags]显示有关集群中主服务器和服务的端口信息。 completionkubectl completion SHELL [options]为指定的 shell (bash 或 zsh)输出 shell 补齐代码。 configkubectl config SUBCOMMAND [flags]修改 kubeconfig 文件。有关详细信息,请参阅各个子命令。 convertkubectl convert -f FILENAME [options]在不同的 API 版本之间转换配置文件。配置文件可以是 YAML 或 JSON 格式。 cordonkubectl cordon NODE [options]将节点标记为不可调度。 cpkubectl cp <file-spec-src> <file-spec-dest> [options]在容器之间复制文件和目录。 createkubectl create -f FILENAME [flags]从文件或 stdin 创建一个或多个资源。 deletekubectl delete (-f FILENAME | TYPE [NAME | /NAME | -l label | --all]) [flags]从文件、标准输入或指定标签选择器、名称、资源选择器或资源中删除资源。 describekubectl describe (-f FILENAME | TYPE [NAME_PREFIX | /NAME | -l label]) [flags]显示一个或多个资源的详细状态。 diffkubectl diff -f FILENAME [flags]将 live 配置和文件或标准输入做对比 (BETA ) drainkubectl drain NODE [options]腾空节点以准备维护。 editkubectl edit (-f FILENAME | TYPE NAME | TYPE/NAME) [flags]使用默认编辑器编辑和更新服务器上一个或多个资源的定义。 execkubectl exec POD [-c CONTAINER] [-i] [-t] [flags] [-- COMMAND [args...]]对 pod 中的容器执行命令。 explainkubectl explain [--recursive=false] [flags]获取多种资源的文档。例如 pod, node, service 等。 exposekubectl expose (-f FILENAME | TYPE NAME | TYPE/NAME) [--port=port] [--protocol=TCP|UDP] [--target-port=number-or-name] [--name=name] [--external-ip=external-ip-of-service] [--type=type] [flags]将副本控制器、服务或 pod 作为新的 Kubernetes 服务暴露。 getkubectl get (-f FILENAME | TYPE [NAME | /NAME | -l label]) [--watch] [--sort-by=FIELD] [[-o | --output]=OUTPUT_FORMAT] [flags]列出一个或多个资源。 kustomizekubectl kustomize <dir> [flags] [options]列出从 kustomization.yaml 文件中的指令生成的一组 API 资源。参数必须是包含文件的目录的路径,或者是 git 存储库 URL,其路径后缀相对于存储库根目录指定了相同的路径。 labelkubectl label (-f FILENAME | TYPE NAME | TYPE/NAME) KEY_1=VAL_1 ... KEY_N=VAL_N [--overwrite] [--all] [--resource-version=version] [flags]添加或更新一个或多个资源的标签。 logskubectl logs POD [-c CONTAINER] [--follow] [flags]在 pod 中打印容器的日志。 optionskubectl options全局命令行选项列表,适用于所有命令。 patchkubectl patch (-f FILENAME | TYPE NAME | TYPE/NAME) --patch PATCH [flags]使用策略合并 patch 程序更新资源的一个或多个字段。 pluginkubectl plugin [flags] [options]提供用于与插件交互的实用程序。 port-forwardkubectl port-forward POD [LOCAL_PORT:]REMOTE_PORT [...[LOCAL_PORT_N:]REMOTE_PORT_N] [flags]将一个或多个本地端口转发到一个 pod。 proxykubectl proxy [--port=PORT] [--www=static-dir] [--www-prefix=prefix] [--api-prefix=prefix] [flags]运行 Kubernetes API 服务器的代理。 replacekubectl replace -f FILENAME从文件或标准输入中替换资源。 rolloutkubectl rollout SUBCOMMAND [options]管理资源的部署。有效的资源类型包括:Deployments, DaemonSets 和 StatefulSets。 runkubectl run NAME --image=image [--env="key=value"] [--port=port] [--dry-run=server | client | none] [--overrides=inline-json] [flags]在集群上运行指定的镜像。 scalekubectl scale (-f FILENAME | TYPE NAME | TYPE/NAME) --replicas=COUNT [--resource-version=version] [--current-replicas=count] [flags]更新指定副本控制器的大小。 setkubectl set SUBCOMMAND [options]配置应用程序资源。 taintkubectl taint NODE NAME KEY_1=VAL_1:TAINT_EFFECT_1 ... KEY_N=VAL_N:TAINT_EFFECT_N [options]更新一个或多个节点上的污点。 topkubectl top [flags] [options]显示资源(CPU/内存/存储)的使用情况。 uncordonkubectl uncordon NODE [options]将节点标记为可调度。 versionkubectl version [--client] [flags]显示运行在客户端和服务器上的 Kubernetes 版本。 waitkubectl wait ([-f FILENAME] | resource.group/resource.name | resource.group [(-l label | --all)]) [--for=delete|--for condition=available] [options]实验性:等待一种或多种资源的特定条件。
了解更多有关命令操作的信息,请参阅 kubectl 参考文档。
资源类型 下表列出所有受支持的资源类型及其缩写别名:
(以下输出可以通过 kubectl api-resources 获取,内容以 Kubernetes 1.19.1 版本为准。)
资源名 缩写名 API 分组 按命名空间 资源类型 bindingstrue Binding componentstatusescsfalse ComponentStatus configmapscmtrue ConfigMap endpointseptrue Endpoints eventsevtrue Event limitrangeslimitstrue LimitRange namespacesnsfalse Namespace nodesnofalse Node persistentvolumeclaimspvctrue PersistentVolumeClaim persistentvolumespvfalse PersistentVolume podspotrue Pod podtemplatestrue PodTemplate replicationcontrollersrctrue ReplicationController resourcequotasquotatrue ResourceQuota secretstrue Secret serviceaccountssatrue ServiceAccount servicessvctrue Service mutatingwebhookconfigurationsadmissionregistration.k8s.io false MutatingWebhookConfiguration validatingwebhookconfigurationsadmissionregistration.k8s.io false ValidatingWebhookConfiguration customresourcedefinitionscrd,crdsapiextensions.k8s.io false CustomResourceDefinition apiservicesapiregistration.k8s.io false APIService controllerrevisionsapps true ControllerRevision daemonsetsdsapps true DaemonSet deploymentsdeployapps true Deployment replicasetsrsapps true ReplicaSet statefulsetsstsapps true StatefulSet tokenreviewsauthentication.k8s.io false TokenReview localsubjectaccessreviewsauthorization.k8s.io true LocalSubjectAccessReview selfsubjectaccessreviewsauthorization.k8s.io false SelfSubjectAccessReview selfsubjectrulesreviewsauthorization.k8s.io false SelfSubjectRulesReview subjectaccessreviewsauthorization.k8s.io false SubjectAccessReview horizontalpodautoscalershpaautoscaling true HorizontalPodAutoscaler cronjobscjbatch true CronJob jobsbatch true Job certificatesigningrequestscsrcertificates.k8s.io false CertificateSigningRequest leasescoordination.k8s.io true Lease endpointslicesdiscovery.k8s.io true EndpointSlice eventsevevents.k8s.io true Event ingressesingextensions true Ingress flowschemasflowcontrol.apiserver.k8s.io false FlowSchema prioritylevelconfigurationsflowcontrol.apiserver.k8s.io false PriorityLevelConfiguration ingressclassesnetworking.k8s.io false IngressClass ingressesingnetworking.k8s.io true Ingress networkpoliciesnetpolnetworking.k8s.io true NetworkPolicy runtimeclassesnode.k8s.io false RuntimeClass poddisruptionbudgetspdbpolicy true PodDisruptionBudget podsecuritypoliciespsppolicy false PodSecurityPolicy clusterrolebindingsrbac.authorization.k8s.io false ClusterRoleBinding clusterrolesrbac.authorization.k8s.io false ClusterRole rolebindingsrbac.authorization.k8s.io true RoleBinding rolesrbac.authorization.k8s.io true Role priorityclassespcscheduling.k8s.io false PriorityClass csidriversstorage.k8s.io false CSIDriver csinodesstorage.k8s.io false CSINode storageclassesscstorage.k8s.io false StorageClass volumeattachmentsstorage.k8s.io false VolumeAttachment
输出选项 有关如何格式化或排序某些命令的输出的信息,请使用以下部分。有关哪些命令支持各种输出选项的详细信息,请参阅kubectl 参考文档。
格式化输出 所有 kubectl 命令的默认输出格式都是人类可读的纯文本格式。要以特定格式向终端窗口输出详细信息,可以将 -o 或 --output 参数添加到受支持的 kubectl 命令中。
语法 kubectl [ command] [ TYPE] [ NAME] -o= <output_format>
根据 kubectl 操作,支持以下输出格式:
Output format Description -o custom-columns=<spec>使用逗号分隔的自定义列 列表打印表。 -o custom-columns-file=<filename>使用 <filename> 文件中的自定义列 模板打印表。 -o json输出 JSON 格式的 API 对象 -o jsonpath=<template>打印 jsonpath 表达式定义的字段 -o jsonpath-file=<filename>打印 <filename> 文件中 jsonpath 表达式定义的字段。 -o name仅打印资源名称而不打印任何其他内容。 -o wide以纯文本格式输出,包含任何附加信息。对于 pod 包含节点名。 -o yaml输出 YAML 格式的 API 对象。
示例 在此示例中,以下命令将单个 pod 的详细信息输出为 YAML 格式的对象:
kubectl get pod web-pod-13je7 -o yaml
请记住:有关每个命令支持哪种输出格式的详细信息,请参阅 kubectl 参考文档。
自定义列 要定义自定义列并仅将所需的详细信息输出到表中,可以使用该 custom-columns 选项。你可以选择内联定义自定义列或使用模板文件:-o=custom-columns=<spec> 或 -o=custom-columns-file=<filename>。
示例 内联:
kubectl get pods <pod-name> -o custom-columns= NAME:.metadata.name,RSRC:.metadata.resourceVersion
模板文件:
kubectl get pods <pod-name> -o custom-columns-file= template.txt
其中,template.txt 文件包含:
NAME RSRC
metadata.name metadata.resourceVersion
运行任何一个命令的结果类似于:
NAME RSRC
submit-queue 610995
Server-side 列 kubectl 支持从服务器接收关于对象的特定列信息。
这意味着对于任何给定的资源,服务器将返回与该资源相关的列和行,以便客户端打印。
通过让服务器封装打印的细节,这允许在针对同一集群使用的客户端之间提供一致的人类可读输出。
此功能默认启用。要禁用它,请将该 --server-print=false 参数添加到 kubectl get 命令中。
例子: 要打印有关 pod 状态的信息,请使用如下命令:
kubectl get pods <pod-name> --server-print= false
输出类似于:
排序列表对象 要将对象排序后输出到终端窗口,可以将 --sort-by 参数添加到支持的 kubectl 命令。通过使用 --sort-by 参数指定任何数字或字符串字段来对对象进行排序。要指定字段,请使用 jsonpath 表达式。
语法 kubectl [ command] [ TYPE] [ NAME] --sort-by= <jsonpath_exp>
示例 要打印按名称排序的 pod 列表,请运行:
kubectl get pods --sort-by= .metadata.name
示例:常用操作 使用以下示例集来帮助你熟悉运行常用 kubectl 操作:
kubectl apply - 以文件或标准输入为准应用或更新资源。
# 使用 example-service.yaml 中的定义创建服务。
kubectl apply -f example-service.yaml
# 使用 example-controller.yaml 中的定义创建 replication controller。
kubectl apply -f example-controller.yaml
# 使用 <directory> 路径下的任意 .yaml, .yml, 或 .json 文件 创建对象。
kubectl apply -f <directory>
kubectl get - 列出一个或多个资源。
# 以纯文本输出格式列出所有 pod。
kubectl get pods
# 以纯文本输出格式列出所有 pod,并包含附加信息(如节点名)。
kubectl get pods -o wide
# 以纯文本输出格式列出具有指定名称的副本控制器。提示:你可以使用别名 'rc' 缩短和替换 'replicationcontroller' 资源类型。
kubectl get replicationcontroller <rc-name>
# 以纯文本输出格式列出所有副本控制器和服务。
kubectl get rc,services
# 以纯文本输出格式列出所有守护程序集,包括未初始化的守护程序集。
kubectl get ds --include-uninitialized
# 列出在节点 server01 上运行的所有 pod
kubectl get pods --field-selector= spec.nodeName= server01
kubectl describe - 显示一个或多个资源的详细状态,默认情况下包括未初始化的资源。
# 显示名称为 <node-name> 的节点的详细信息。
kubectl describe nodes <node-name>
# 显示名为 <pod-name> 的 pod 的详细信息。
kubectl describe pods/<pod-name>
# 显示由名为 <rc-name> 的副本控制器管理的所有 pod 的详细信息。
# 记住:副本控制器创建的任何 pod 都以复制控制器的名称为前缀。
kubectl describe pods <rc-name>
# 描述所有的 pod,不包括未初始化的 pod
kubectl describe pods
说明: kubectl get 命令通常用于检索同一资源类型的一个或多个资源。
它具有丰富的参数,允许你使用 -o 或 --output 参数自定义输出格式。你可以指定 -w 或 --watch 参数以开始观察特定对象的更新。
kubectl describe 命令更侧重于描述指定资源的许多相关方面。它可以调用对 API 服务器 的多个 API 调用来为用户构建视图。
例如,该 kubectl describe node 命令不仅检索有关节点的信息,还检索在其上运行的 pod 的摘要,为节点生成的事件等。
kubectl delete - 从文件、stdin 或指定标签选择器、名称、资源选择器或资源中删除资源。
# 使用 pod.yaml 文件中指定的类型和名称删除 pod。
kubectl delete -f pod.yaml
# 删除所有带有 '<label-key>=<label-value>' 标签的 Pod 和服务。
kubectl delete pods,services -l <label-key>= <label-value>
# 删除所有 pod,包括未初始化的 pod。
kubectl delete pods --all
kubectl exec - 对 pod 中的容器执行命令。
# 从 pod <pod-name> 中获取运行 'date' 的输出。默认情况下,输出来自第一个容器。
kubectl exec <pod-name> -- date
# 运行输出 'date' 获取在容器的 <container-name> 中 pod <pod-name> 的输出。
kubectl exec <pod-name> -c <container-name> -- date
# 获取一个交互 TTY 并运行 /bin/bash <pod-name >。默认情况下,输出来自第一个容器。
kubectl exec -ti <pod-name> -- /bin/bash
kubectl logs - 打印 Pod 中容器的日志。
# 从 pod 返回日志快照。
kubectl logs <pod-name>
# 从 pod <pod-name> 开始流式传输日志。这类似于 'tail -f' Linux 命令。
kubectl logs -f <pod-name>
示例:创建和使用插件 使用以下示例来帮助你熟悉编写和使用 kubectl 插件:
# 用任何语言创建一个简单的插件,并为生成的可执行文件命名
# 以前缀 "kubectl-" 开始
cat ./kubectl-hello
#!/bin/sh
# 这个插件打印单词 "hello world"
echo "hello world"
这个插件写好了,把它变成可执行的:
sudo chmod a+x ./kubectl-hello
# 并将其移动到路径中的某个位置
sudo mv ./kubectl-hello /usr/local/bin
sudo chown root:root /usr/local/bin
# 你现在已经创建并"安装了"一个 kubectl 插件。
# 你可以开始使用这个插件,从 kubectl 调用它,就像它是一个常规命令一样
kubectl hello
hello world
# 你可以"卸载"一个插件,只需从你的路径中删除它
sudo rm /usr/local/bin/kubectl-hello
为了查看可用的所有 kubectl 插件,你可以使用 kubectl plugin list 子命令:
输出类似于:
The following kubectl-compatible plugins are available:
/usr/local/bin/kubectl-hello
/usr/local/bin/kubectl-foo
/usr/local/bin/kubectl-bar
kubectl plugin list指令也可以向你告警哪些插件被运行,或是被其它插件覆盖了,例如:
sudo chmod -x /usr/local/bin/kubectl-foo # 删除执行权限
kubectl plugin list
The following kubectl-compatible plugins are available:
/usr/local/bin/kubectl-hello
/usr/local/bin/kubectl-foo
- warning: /usr/local/bin/kubectl-foo identified as a plugin, but it is not executable
/usr/local/bin/kubectl-bar
error: one plugin warning was found
你可以将插件视为在现有 kubectl 命令之上构建更复杂功能的一种方法:
接下来的几个示例假设你已经将 kubectl-whoami 设置为以下内容:
#!/bin/bash
#这个插件利用 `kubectl config` 命令基于当前所选上下文输出当前用户的信息
kubectl config view --template= '{{ range .contexts }}{{ if eq .name "' $( kubectl config current-context) '" }}Current user: {{ printf "%s\n" .context.user }}{{ end }}{{ end }}'
运行以上命令将为你提供一个输出,其中包含 KUBECONFIG 文件中当前上下文的用户:
#!/bin/bash
# 使文件成为可执行的
sudo chmod +x ./kubectl-whoami
# 然后移动到你的路径中
sudo mv ./kubectl-whoami /usr/local/bin
kubectl whoami
Current user: plugins-user
要了解关于插件的更多信息,请查看示例 cli 插件 。
接下来 6.8.2 - JSONPath 支持 Kubectl 支持 JSONPath 模板。
JSONPath 模板由 {} 包起来的 JSONPath 表达式组成。Kubectl 使用 JSONPath 表达式来过滤 JSON 对象中的特定字段并格式化输出。除了原始的 JSONPath 模板语法,以下函数和语法也是有效的:
使用双引号将 JSONPath 表达式内的文本引起来。 使用 range,end 运算符来迭代列表。 使用负片索引后退列表。负索引不会“环绕”列表,并且只要 -index + listLength> = 0 就有效。 给定 JSON 输入:
{
"kind" : "List" ,
"items" :[
{
"kind" :"None" ,
"metadata" :{"name" :"127.0.0.1" },
"status" :{
"capacity" :{"cpu" :"4" },
"addresses" :[{"type" : "LegacyHostIP" , "address" :"127.0.0.1" }]
}
},
{
"kind" :"None" ,
"metadata" :{"name" :"127.0.0.2" },
"status" :{
"capacity" :{"cpu" :"8" },
"addresses" :[
{"type" : "LegacyHostIP" , "address" :"127.0.0.2" },
{"type" : "another" , "address" :"127.0.0.3" }
]
}
}
],
"users" :[
{
"name" : "myself" ,
"user" : {}
},
{
"name" : "e2e" ,
"user" : {"username" : "admin" , "password" : "secret" }
}
]
}
函数 描述 示例 结果 text纯文本 kind is {.kind}kind is List@当前对象 {@}与输入相同 . or []子运算符 {.kind}, {['kind']} or {['name\.type']}List..递归下降 {..name}127.0.0.1 127.0.0.2 myself e2e*通配符。获取所有对象 {.items[*].metadata.name}[127.0.0.1 127.0.0.2][start:end :step]下标运算符 {.users[0].name}myself[,]并集运算符 {.items[*]['metadata.name', 'status.capacity']}127.0.0.1 127.0.0.2 map[cpu:4] map[cpu:8]?()过滤 {.users[?(@.name=="e2e")].user.password}secretrange, end迭代列表 {range .items[*]}[{.metadata.name}, {.status.capacity}] {end}[127.0.0.1, map[cpu:4]] [127.0.0.2, map[cpu:8]]''引用解释执行字符串 {range .items[*]}{.metadata.name}{'\t'}{end}127.0.0.1 127.0.0.2
使用 kubectl 和 JSONPath 表达式的示例:
kubectl get pods -o json
kubectl get pods -o= jsonpath = '{@}'
kubectl get pods -o= jsonpath = '{.items[0]}'
kubectl get pods -o= jsonpath = '{.items[0].metadata.name}'
kubectl get pods -o= jsonpath = "{.items[*]['metadata.name', 'status.capacity']}"
kubectl get pods -o= jsonpath = '{range .items[*]}{.metadata.name}{"\t"}{.status.startTime}{"\n"}{end}'
说明: 在 Windows 上,您必须用双引号把任何包含空格的 JSONPath 模板(不是上面 bash 所示的单引号)。
反过来,这意味着您必须在模板中的所有文字周围使用单引号或转义的双引号。
例如:
C:\ > kubectl get pods -o=jsonpath="{range .items[*]}{.metadata.name}{'\t'}{.status.startTime}{'\n'}{end}"
C:\ > kubectl get pods -o=jsonpath="{range .items[*]}{.metadata.name}{\"\t\"}{.status.startTime}{\"\n\"}{end}"
说明: 不支持 JSONPath 正则表达式。如需使用正则表达式进行匹配操作,您可以使用如 jq 之类的工具。
# kubectl 的 JSONpath 输出不支持正则表达式
# 下面的命令不会生效
kubectl get pods -o jsonpath = '{.items[?(@.metadata.name=~/^test$/)].metadata.name}'
# 下面的命令可以获得所需的结果
kubectl get pods -o json | jq -r '.items[] | select(.metadata.name | test("test-")).spec.containers[].image'
6.8.3 - kubectl 简介 kubectl 管理控制 Kubernetes 集群。
获取更多信息,请访问 kubectl 概述 。
kubectl [flags]
选项 --add-dir-header 设置为 true 表示添加文件目录到日志信息头中 --alsologtostderr 表示将日志输出到文件的同时输出到 stderr --as string 以指定用户的身份执行操作 --as-group stringArray 模拟指定的组来执行操作,可以使用这个标志来指定多个组。 --azure-container-registry-config string 包含 Azure 容器仓库配置信息的文件的路径。 --cache-dir string 默认值: "$HOME/.kube/cache" 默认缓存目录 --certificate-authority string 指向证书机构的 cert 文件路径 --client-certificate string TLS 使用的客户端证书路径 --client-key string TLS 使用的客户端密钥文件路径 --cloud-provider-gce-l7lb-src-cidrs cidrs 默认值: 130.211.0.0/22,35.191.0.0/16 在 GCE 防火墙中开放的 CIDR,用来进行 L7 LB 流量代理和健康检查。 --cloud-provider-gce-lb-src-cidrs cidrs 默认值: 130.211.0.0/22,209.85.152.0/22,209.85.204.0/22,35.191.0.0/16 在 GCE 防火墙中开放的 CIDR,用来进行 L4 LB 流量代理和健康检查。 --cluster string 要使用的 kubeconfig 集群的名称 --context string 要使用的 kubeconfig 上下文的名称 --default-not-ready-toleration-seconds int 默认值: 300 表示 `notReady` 状态的容忍度秒数:默认情况下,`NoExecute` 被添加到尚未具有此容忍度的每个 Pod 中。 --default-unreachable-toleration-seconds int 默认值: 300 表示 `unreachable` 状态的容忍度秒数:默认情况下,`NoExecute` 被添加到尚未具有此容忍度的每个 Pod 中。 -h, --help kubectl 操作的帮助命令 --insecure-skip-tls-verify 设置为 true,则表示不会检查服务器证书的有效性。这样会导致您的 HTTPS 连接不安全。 --kubeconfig string CLI 请求使用的 kubeconfig 配置文件的路径。 --log-backtrace-at traceLocation 默认值: 0 当日志机制运行到指定文件的指定行(file:N)时,打印调用堆栈信息 --log-dir string 如果不为空,则将日志文件写入此目录 --log-file string 如果不为空,则将使用此日志文件 --log-file-max-size uint 默认值: 1800 定义日志文件的最大尺寸。单位为兆字节。如果值设置为 0,则表示日志文件大小不受限制。 --log-flush-frequency duration 默认值: 5s 两次日志刷新操作之间的最长时间(秒) --logtostderr 默认值: true 日志输出到 stderr 而不是文件中 --match-server-version 要求客户端版本和服务端版本相匹配 -n, --namespace string 如果存在,CLI 请求将使用此命名空间 --one-output 如果为 true,则只将日志写入初始严重级别(而不是同时写入所有较低的严重级别)。 --password string API 服务器进行基本身份验证的密码 --profile string 默认值: "none" 要记录的性能指标的名称。可取 (none|cpu|heap|goroutine|threadcreate|block|mutex) 其中之一。 --profile-output string 默认值: "profile.pprof" 用于转储所记录的性能信息的文件名 --request-timeout string 默认值: "0" 放弃单个服务器请求之前的等待时间,非零值需要包含相应时间单位(例如:1s、2m、3h)。零值则表示不做超时要求。 -s, --server string Kubernetes API 服务器的地址和端口 --skip-headers 设置为 true 则表示跳过在日志消息中出现 header 前缀信息 --skip-log-headers 设置为 true 则表示在打开日志文件时跳过 header 信息 --stderrthreshold severity 默认值: 2 等于或高于此阈值的日志将输出到标准错误输出(stderr) --token string 用于对 API 服务器进行身份认证的持有者令牌 --user string 指定使用 kubeconfig 配置文件中的用户名 --username string 用于 API 服务器的基本身份验证的用户名 -v, --v Level 指定输出日志的日志详细级别 --version version[=true] 打印 kubectl 版本信息并退出 --vmodule moduleSpec 以逗号分隔的 pattern=N 设置列表,用于过滤文件的日志记录
另请参见 6.8.4 - kubectl 命令 kubectl 命令参考
6.8.5 - kubectl 备忘单 本页列举了常用的 “kubectl” 命令和标志
Kubectl 自动补全 BASH source <( kubectl completion bash) # 在 bash 中设置当前 shell 的自动补全,要先安装 bash-completion 包。
echo "source <(kubectl completion bash)" >> ~/.bashrc # 在您的 bash shell 中永久的添加自动补全
您还可以为 kubectl 使用一个速记别名,该别名也可以与 completion 一起使用:
alias k = kubectl
complete -F __start_kubectl k
ZSH source <( kubectl completion zsh) # 在 zsh 中设置当前 shell 的自动补全
echo "[[ $commands [kubectl] ]] && source <(kubectl completion zsh)" >> ~/.zshrc # 在您的 zsh shell 中永久的添加自动补全
Kubectl 上下文和配置 设置 kubectl 与哪个 Kubernetes 集群进行通信并修改配置信息。
查看使用 kubeconfig 跨集群授权访问
文档获取配置文件详细信息。
kubectl config view # 显示合并的 kubeconfig 配置。
# 同时使用多个 kubeconfig 文件并查看合并的配置
KUBECONFIG = ~/.kube/config:~/.kube/kubconfig2 kubectl config view
# 获取 e2e 用户的密码
kubectl config view -o jsonpath = '{.users[?(@.name == "e2e")].user.password}'
kubectl config view -o jsonpath = '{.users[].name}' # 显示第一个用户
kubectl config view -o jsonpath = '{.users[*].name}' # 获取用户列表
kubectl config get-contexts # 显示上下文列表
kubectl config current-context # 展示当前所处的上下文
kubectl config use-context my-cluster-name # 设置默认的上下文为 my-cluster-name
# 添加新的用户配置到 kubeconf 中,使用 basic auth 进行身份认证
kubectl config set-credentials kubeuser/foo.kubernetes.com --username= kubeuser --password= kubepassword
# 在指定上下文中持久性地保存名字空间,供所有后续 kubectl 命令使用
kubectl config set-context --current --namespace= ggckad-s2
# 使用特定的用户名和名字空间设置上下文
kubectl config set-context gce --user= cluster-admin --namespace= foo \
&& kubectl config use-context gce
kubectl config unset users.foo # 删除用户 foo
Kubectl apply apply 通过定义 Kubernetes 资源的文件来管理应用。
它通过运行 kubectl apply 在集群中创建和更新资源。
这是在生产中管理 Kubernetes 应用的推荐方法。
参见 Kubectl 文档 。
创建对象 Kubernetes 配置可以用 YAML 或 JSON 定义。可以使用的文件扩展名有
.yaml、.yml 和 .json。
kubectl apply -f ./my-manifest.yaml # 创建资源
kubectl apply -f ./my1.yaml -f ./my2.yaml # 使用多个文件创建
kubectl apply -f ./dir # 基于目录下的所有清单文件创建资源
kubectl apply -f https://git.io/vPieo # 从 URL 中创建资源
kubectl create deployment nginx --image= nginx # 启动单实例 nginx
# 创建一个打印 “Hello World” 的 Job
kubectl create job hello --image= busybox -- echo "Hello World"
# 创建一个打印 “Hello World” 间隔1分钟的 CronJob
kubectl create cronjob hello --image= busybox --schedule= "*/1 * * * *" -- echo "Hello World"
kubectl explain pods # 获取 pod 清单的文档说明
# 从标准输入创建多个 YAML 对象
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
name: busybox-sleep
spec:
containers:
- name: busybox
image: busybox
args:
- sleep
- "1000000"
---
apiVersion: v1
kind: Pod
metadata:
name: busybox-sleep-less
spec:
containers:
- name: busybox
image: busybox
args:
- sleep
- "1000"
EOF
# 创建有多个 key 的 Secret
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Secret
metadata:
name: mysecret
type: Opaque
data:
password: $(echo -n "s33msi4" | base64 -w0)
username: $(echo -n "jane" | base64 -w0)
EOF
查看和查找资源 # get 命令的基本输出
kubectl get services # 列出当前命名空间下的所有 services
kubectl get pods --all-namespaces # 列出所有命名空间下的全部的 Pods
kubectl get pods -o wide # 列出当前命名空间下的全部 Pods,并显示更详细的信息
kubectl get deployment my-dep # 列出某个特定的 Deployment
kubectl get pods # 列出当前命名空间下的全部 Pods
kubectl get pod my-pod -o yaml # 获取一个 pod 的 YAML
# describe 命令的详细输出
kubectl describe nodes my-node
kubectl describe pods my-pod
# 列出当前名字空间下所有 Services,按名称排序
kubectl get services --sort-by= .metadata.name
# 列出 Pods,按重启次数排序
kubectl get pods --sort-by= '.status.containerStatuses[0].restartCount'
# 列举所有 PV 持久卷,按容量排序
kubectl get pv --sort-by= .spec.capacity.storage
# 获取包含 app=cassandra 标签的所有 Pods 的 version 标签
kubectl get pods --selector= app = cassandra -o \
jsonpath = '{.items[*].metadata.labels.version}'
# 检索带有 “.” 键值,例: 'ca.crt'
kubectl get configmap myconfig \
-o jsonpath = '{.data.ca\.crt}'
# 获取所有工作节点(使用选择器以排除标签名称为 'node-role.kubernetes.io/master' 的结果)
kubectl get node --selector= '!node-role.kubernetes.io/master'
# 获取当前命名空间中正在运行的 Pods
kubectl get pods --field-selector= status.phase= Running
# 获取全部节点的 ExternalIP 地址
kubectl get nodes -o jsonpath = '{.items[*].status.addresses[?(@.type=="ExternalIP")].address}'
# 列出属于某个特定 RC 的 Pods 的名称
# 在转换对于 jsonpath 过于复杂的场合,"jq" 命令很有用;可以在 https://stedolan.github.io/jq/ 找到它。
sel = ${ $( kubectl get rc my-rc --output= json | jq -j '.spec.selector | to_entries | .[] | "\(.key)=\(.value),"' ) %?}
echo $( kubectl get pods --selector= $sel --output= jsonpath ={ .items..metadata.name} )
# 显示所有 Pods 的标签(或任何其他支持标签的 Kubernetes 对象)
kubectl get pods --show-labels
# 检查哪些节点处于就绪状态
JSONPATH = '{range .items[*]}{@.metadata.name}:{range @.status.conditions[*]}{@.type}={@.status};{end}{end}' \
&& kubectl get nodes -o jsonpath = " $JSONPATH " | grep "Ready=True"
# 列出被一个 Pod 使用的全部 Secret
kubectl get pods -o json | jq '.items[].spec.containers[].env[]?.valueFrom.secretKeyRef.name' | grep -v null | sort | uniq
# 列举所有 Pods 中初始化容器的容器 ID(containerID)
# Helpful when cleaning up stopped containers, while avoiding removal of initContainers.
kubectl get pods --all-namespaces -o jsonpath = '{range .items[*].status.initContainerStatuses[*]}{.containerID}{"\n"}{end}' | cut -d/ -f3
# 列出事件(Events),按时间戳排序
kubectl get events --sort-by= .metadata.creationTimestamp
# 比较当前的集群状态和假定某清单被应用之后的集群状态
kubectl diff -f ./my-manifest.yaml
# 生成一个句点分隔的树,其中包含为节点返回的所有键
# 在复杂的嵌套JSON结构中定位键时非常有用
kubectl get nodes -o json | jq -c 'path(..)|[.[]|tostring]|join(".")'
# 生成一个句点分隔的树,其中包含为pod等返回的所有键
kubectl get pods -o json | jq -c 'path(..)|[.[]|tostring]|join(".")'
更新资源 kubectl set image deployment/frontend www = image:v2 # 滚动更新 "frontend" Deployment 的 "www" 容器镜像
kubectl rollout history deployment/frontend # 检查 Deployment 的历史记录,包括版本
kubectl rollout undo deployment/frontend # 回滚到上次部署版本
kubectl rollout undo deployment/frontend --to-revision= 2 # 回滚到特定部署版本
kubectl rollout status -w deployment/frontend # 监视 "frontend" Deployment 的滚动升级状态直到完成
kubectl rollout restart deployment/frontend # 轮替重启 "frontend" Deployment
cat pod.json | kubectl replace -f - # 通过传入到标准输入的 JSON 来替换 Pod
# 强制替换,删除后重建资源。会导致服务不可用。
kubectl replace --force -f ./pod.json
# 为多副本的 nginx 创建服务,使用 80 端口提供服务,连接到容器的 8000 端口。
kubectl expose rc nginx --port= 80 --target-port= 8000
# 将某单容器 Pod 的镜像版本(标签)更新到 v4
kubectl get pod mypod -o yaml | sed 's/\(image: myimage\):.*$/\1:v4/' | kubectl replace -f -
kubectl label pods my-pod new-label= awesome # 添加标签
kubectl annotate pods my-pod icon-url= http://goo.gl/XXBTWq # 添加注解
kubectl autoscale deployment foo --min= 2 --max= 10 # 对 "foo" Deployment 自动伸缩容
部分更新资源 # 部分更新某节点
kubectl patch node k8s-node-1 -p '{"spec":{"unschedulable":true}}'
# 更新容器的镜像;spec.containers[*].name 是必须的。因为它是一个合并性质的主键。
kubectl patch pod valid-pod -p '{"spec":{"containers":[{"name":"kubernetes-serve-hostname","image":"new image"}]}}'
# 使用带位置数组的 JSON patch 更新容器的镜像
kubectl patch pod valid-pod --type= 'json' -p= '[{"op": "replace", "path": "/spec/containers/0/image", "value":"new image"}]'
# 使用带位置数组的 JSON patch 禁用某 Deployment 的 livenessProbe
kubectl patch deployment valid-deployment --type json -p= '[{"op": "remove", "path": "/spec/template/spec/containers/0/livenessProbe"}]'
# 在带位置数组中添加元素
kubectl patch sa default --type= 'json' -p= '[{"op": "add", "path": "/secrets/1", "value": {"name": "whatever" } }]'
编辑资源 使用你偏爱的编辑器编辑 API 资源。
kubectl edit svc/docker-registry # 编辑名为 docker-registry 的服务
KUBE_EDITOR = "nano" kubectl edit svc/docker-registry # 使用其他编辑器
对资源进行伸缩 kubectl scale --replicas= 3 rs/foo # 将名为 'foo' 的副本集伸缩到 3 副本
kubectl scale --replicas= 3 -f foo.yaml # 将在 "foo.yaml" 中的特定资源伸缩到 3 个副本
kubectl scale --current-replicas= 2 --replicas= 3 deployment/mysql # 如果名为 mysql 的 Deployment 的副本当前是 2,那么将它伸缩到 3
kubectl scale --replicas= 5 rc/foo rc/bar rc/baz # 伸缩多个副本控制器
删除资源 kubectl delete -f ./pod.json # 删除在 pod.json 中指定的类型和名称的 Pod
kubectl delete pod,service baz foo # 删除名称为 "baz" 和 "foo" 的 Pod 和服务
kubectl delete pods,services -l name = myLabel # 删除包含 name=myLabel 标签的 pods 和服务
kubectl -n my-ns delete pod,svc --all # 删除在 my-ns 名字空间中全部的 Pods 和服务
# 删除所有与 pattern1 或 pattern2 awk 模式匹配的 Pods
kubectl get pods -n mynamespace --no-headers= true | awk '/pattern1|pattern2/{print $1}' | xargs kubectl delete -n mynamespace pod
与运行中的 Pods 进行交互 kubectl logs my-pod # 获取 pod 日志(标准输出)
kubectl logs -l name = myLabel # 获取含 name=myLabel 标签的 Pods 的日志(标准输出)
kubectl logs my-pod --previous # 获取上个容器实例的 pod 日志(标准输出)
kubectl logs my-pod -c my-container # 获取 Pod 容器的日志(标准输出, 多容器场景)
kubectl logs -l name = myLabel -c my-container # 获取含 name=myLabel 标签的 Pod 容器日志(标准输出, 多容器场景)
kubectl logs my-pod -c my-container --previous # 获取 Pod 中某容器的上个实例的日志(标准输出, 多容器场景)
kubectl logs -f my-pod # 流式输出 Pod 的日志(标准输出)
kubectl logs -f my-pod -c my-container # 流式输出 Pod 容器的日志(标准输出, 多容器场景)
kubectl logs -f -l name = myLabel --all-containers # 流式输出含 name=myLabel 标签的 Pod 的所有日志(标准输出)
kubectl run -i --tty busybox --image= busybox -- sh # 以交互式 Shell 运行 Pod
kubectl run nginx --image= nginx -n mynamespace # 在指定名字空间中运行 nginx Pod
kubectl run nginx --image= nginx # 运行 ngins Pod 并将其规约写入到名为 pod.yaml 的文件
--dry-run= client -o yaml > pod.yaml
kubectl attach my-pod -i # 挂接到一个运行的容器中
kubectl port-forward my-pod 5000:6000 # 在本地计算机上侦听端口 5000 并转发到 my-pod 上的端口 6000
kubectl exec my-pod -- ls / # 在已有的 Pod 中运行命令(单容器场景)
kubectl exec --stdin --tty my-pod -- /bin/sh # 使用交互 shell 访问正在运行的 Pod (一个容器场景)
kubectl exec my-pod -c my-container -- ls / # 在已有的 Pod 中运行命令(多容器场景)
kubectl top pod POD_NAME --containers # 显示给定 Pod 和其中容器的监控数据
与节点和集群进行交互 kubectl cordon my-node # 标记 my-node 节点为不可调度
kubectl drain my-node # 对 my-node 节点进行清空操作,为节点维护做准备
kubectl uncordon my-node # 标记 my-node 节点为可以调度
kubectl top node my-node # 显示给定节点的度量值
kubectl cluster-info # 显示主控节点和服务的地址
kubectl cluster-info dump # 将当前集群状态转储到标准输出
kubectl cluster-info dump --output-directory= /path/to/cluster-state # 将当前集群状态输出到 /path/to/cluster-state
# 如果已存在具有指定键和效果的污点,则替换其值为指定值。
kubectl taint nodes foo dedicated = special-user:NoSchedule
资源类型 列出所支持的全部资源类型和它们的简称、API 组 , 是否是名字空间作用域 和 Kind 。
用于探索 API 资源的其他操作:
kubectl api-resources --namespaced= true # 所有命名空间作用域的资源
kubectl api-resources --namespaced= false # 所有非命名空间作用域的资源
kubectl api-resources -o name # 用简单格式列举所有资源(仅显示资源名称)
kubectl api-resources -o wide # 用扩展格式列举所有资源(又称 "wide" 格式)
kubectl api-resources --verbs= list,get # 支持 "list" 和 "get" 请求动词的所有资源
kubectl api-resources --api-group= extensions # "extensions" API 组中的所有资源
格式化输出 要以特定格式将详细信息输出到终端窗口,将 -o(或者 --output)参数添加到支持的 kubectl 命令中。
输出格式 描述 -o=custom-columns=<spec>使用逗号分隔的自定义列来打印表格 -o=custom-columns-file=<filename>使用 <filename> 文件中的自定义列模板打印表格 -o=json输出 JSON 格式的 API 对象 -o=jsonpath=<template>打印 jsonpath 表达式中定义的字段 -o=jsonpath-file=<filename>打印在 <filename> 文件中定义的 jsonpath 表达式所指定的字段。 -o=name仅打印资源名称而不打印其他内容 -o=wide以纯文本格式输出额外信息,对于 Pod 来说,输出中包含了节点名称 -o=yaml输出 YAML 格式的 API 对象
使用 -o=custom-columns 的示例:
# 集群中运行着的所有镜像
kubectl get pods -A -o= custom-columns= 'DATA:spec.containers[*].image'
# 除 "k8s.gcr.io/coredns:1.6.2" 之外的所有镜像
kubectl get pods -A -o= custom-columns= 'DATA:spec.containers[?(@.image!="k8s.gcr.io/coredns:1.6.2")].image'
# 输出 metadata 下面的所有字段,无论 Pod 名字为何
kubectl get pods -A -o= custom-columns= 'DATA:metadata.*'
有关更多示例,请参看 kubectl 参考文档 。
Kubectl 日志输出详细程度和调试 Kubectl 日志输出详细程度是通过 -v 或者 --v 来控制的,参数后跟一个数字表示日志的级别。
Kubernetes 通用的日志习惯和相关的日志级别在
这里 有相应的描述。
详细程度 描述 --v=0用于那些应该 始终 对运维人员可见的信息,因为这些信息一般很有用。 --v=1如果您不想要看到冗余信息,此值是一个合理的默认日志级别。 --v=2输出有关服务的稳定状态的信息以及重要的日志消息,这些信息可能与系统中的重大变化有关。这是建议大多数系统设置的默认日志级别。 --v=3包含有关系统状态变化的扩展信息。 --v=4包含调试级别的冗余信息。 --v=5跟踪级别的详细程度。 --v=6显示所请求的资源。 --v=7显示 HTTP 请求头。 --v=8显示 HTTP 请求内容。 --v=9显示 HTTP 请求内容而且不截断内容。
接下来 6.8.6 - kubectl 的用法约定 kubectl 的推荐用法约定。
在可重用脚本中使用 kubectl 对于脚本中的稳定输出:
请求一个面向机器的输出格式,例如 -o name、-o json、-o yaml、-o go template 或 -o jsonpath。 完全限定版本。例如 jobs.v1.batch/myjob。这将确保 kubectl 不会使用其默认版本,该版本会随着时间的推移而更改。 不要依赖上下文、首选项或其他隐式状态。 最佳实践 kubectl run若希望 kubectl run 满足基础设施即代码的要求:
使用特定版本的标签标记镜像,不要将该标签移动到新版本。例如,使用 :v1234、v1.2.3、r03062016-1-4,而不是 :latest(有关详细信息,请参阅配置的最佳实践 )。 使用基于版本控制的脚本来运行包含大量参数的镜像。 对于无法通过 kubectl run 参数来表示的功能特性,使用基于源码控制的配置文件,以记录要使用的功能特性。 你可以使用 --dry-run=client 参数来预览而不真正提交即将下发到集群的对象实例:
说明: 所有的 kubectl run 生成器已弃用。
查阅 Kubernetes v1.17 文档中的生成器列表 以及它们的用法。
生成器 你可以使用 kubectl 命令生成以下资源, kubectl create --dry-run=client -o yaml:
clusterrole: 创建 ClusterRole。clusterrolebinding: 为特定的 ClusterRole 创建 ClusterRoleBinding。configmap: 使用本地文件、目录或文本值创建 Configmap。cronjob: 使用指定的名称创建 Cronjob。deployment: 使用指定的名称创建 Deployment。job: 使用指定的名称创建 Job。namespace: 使用指定的名称创建名称空间。poddisruptionbudget: 使用指定名称创建 Pod 干扰预算。priorityclass: 使用指定的名称创建 Priorityclass。quota: 使用指定的名称创建配额。role: 使用单一规则创建角色。rolebinding: 为特定角色或 ClusterRole 创建 RoleBinding。secret: 使用指定的子命令创建 Secret。service: 使用指定的子命令创建服务。serviceaccount: 使用指定的名称创建服务帐户。kubectl apply您可以使用 kubectl apply 命令创建或更新资源。有关使用 kubectl apply 更新资源的详细信息,请参阅 Kubectl 文档 。 6.8.7 - 适用于 Docker 用户的 kubectl 您可以使用 Kubernetes 命令行工具 kubectl 与 API 服务器进行交互。如果您熟悉 Docker 命令行工具,则使用 kubectl 非常简单。但是,docker 命令和 kubectl 命令之间有一些区别。以下显示了 docker 子命令,并描述了等效的 kubectl 命令。
docker run 要运行 nginx 部署并将其暴露,请参见kubectl create deployment
docker:
docker run -d --restart= always -e DOMAIN = cluster --name nginx-app -p 80:80 nginx
55c103fa129692154a7652490236fee9be47d70a8dd562281ae7d2f9a339a6db
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
55c103fa1296 nginx "nginx -g 'daemon of…" 9 seconds ago Up 9 seconds 0.0.0.0:80->80/tcp nginx-app
kubectl:
# 启动运行 nginx 的 Pod
kubectl create deployment --image= nginx nginx-app
deployment.apps/nginx-app created
# add env to nginx-app
kubectl set env deployment/nginx-app DOMAIN = cluster
deployment.apps/nginx-app env updated
说明: kubectl 命令打印创建或突变资源的类型和名称,然后可以在后续命令中使用。部署后,您可以公开新服务。
# 通过服务公开端口
kubectl expose deployment nginx-app --port= 80 --name= nginx-http
service "nginx-http" exposed
在 kubectl 命令中,我们创建了一个 Deployment ,这将保证有 N 个运行 nginx 的 pod(N 代表 spec 中声明的 replica 数,默认为 1)。我们还创建了一个 service ,其选择器与容器标签匹配。查看使用服务访问群集中的应用程序 获取更多信息。
默认情况下镜像会在后台运行,与 docker run -d ... 类似,如果您想在前台运行,使用 kubectl run 在前台运行 Pod:
kubectl run [ -i] [ --tty] --attach <name> --image= <image>
与 docker run ... 不同的是,如果指定了 --attach ,我们将连接到 stdin,stdout 和 stderr,而不能控制具体连接到哪个输出流(docker -a ...)。要从容器中退出,可以输入 Ctrl + P,然后按 Ctrl + Q。
因为我们使用 Deployment 启动了容器,如果您终止连接到的进程(例如 ctrl-c),容器将会重启,这跟 docker run -it 不同。
如果想销毁该 Deployment(和它的 pod),您需要运行 kubectl delete deployment <name>。
docker ps 如何列出哪些正在运行?查看 kubectl get 。
使用 docker 命令:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
14636241935f ubuntu:16.04 "echo test" 5 seconds ago Exited (0) 5 seconds ago cocky_fermi
55c103fa1296 nginx "nginx -g 'daemon of…" About a minute ago Up About a minute 0.0.0.0:80->80/tcp nginx-app
使用 kubectl 命令:
NAME READY STATUS RESTARTS AGE
nginx-app-8df569cb7-4gd89 1/1 Running 0 3m
ubuntu 0/1 Completed 0 20s
docker attach 如何连接到已经运行在容器中的进程?查看 kubectl attach 。
使用 docker 命令:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
55c103fa1296 nginx "nginx -g 'daemon of…" 5 minutes ago Up 5 minutes 0.0.0.0:80->80/tcp nginx-app
docker attach 55c103fa1296
...
kubectl:
NAME READY STATUS RESTARTS AGE
nginx-app-5jyvm 1/1 Running 0 10m
kubectl attach -it nginx-app-5jyvm
...
要从容器中分离,可以输入 Ctrl + P,然后按 Ctrl + Q。
docker exec 如何在容器中执行命令?查看 kubectl exec 。
使用 docker 命令:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
55c103fa1296 nginx "nginx -g 'daemon of…" 6 minutes ago Up 6 minutes 0.0.0.0:80->80/tcp nginx-app
docker exec 55c103fa1296 cat /etc/hostname
55c103fa1296
使用 kubectl 命令:
NAME READY STATUS RESTARTS AGE
nginx-app-5jyvm 1/1 Running 0 10m
kubectl exec nginx-app-5jyvm -- cat /etc/hostname
nginx-app-5jyvm
执行交互式命令怎么办?
使用 docker 命令:
docker exec -ti 55c103fa1296 /bin/sh
# exit
kubectl:
kubectl exec -ti nginx-app-5jyvm -- /bin/sh
# exit
更多信息请查看获取运行中容器的 Shell 环境 。
docker logs 如何查看运行中进程的 stdout/stderr?查看 kubectl logs 。
使用 docker 命令:
192.168.9.1 - - [14/Jul/2015:01:04:02 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.35.0" "-"
192.168.9.1 - - [14/Jul/2015:01:04:03 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.35.0" "-"
使用 kubectl 命令:
kubectl logs -f nginx-app-zibvs
10.240.63.110 - - [14/Jul/2015:01:09:01 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.26.0" "-"
10.240.63.110 - - [14/Jul/2015:01:09:02 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.26.0" "-"
现在是时候提一下 pod 和容器之间的细微差别了;默认情况下如果 pod 中的进程退出 pod 也不会终止,相反它将会重启该进程。这类似于 docker run 时的 --restart=always 选项, 这是主要差别。在 docker 中,进程的每个调用的输出都是被连接起来的,但是对于 kubernetes,每个调用都是分开的。要查看以前在 kubernetes 中执行的输出,请执行以下操作:
kubectl logs --previous nginx-app-zibvs
10.240.63.110 - - [14/Jul/2015:01:09:01 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.26.0" "-"
10.240.63.110 - - [14/Jul/2015:01:09:02 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.26.0" "-"
查看日志架构 获取更多信息。
docker stop and docker rm 如何停止和删除运行中的进程?查看 kubectl delete 。
使用 docker 命令:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
a9ec34d98787 nginx "nginx -g 'daemon of" 22 hours ago Up 22 hours 0.0.0.0:80->80/tcp, 443/tcp nginx-app
a9ec34d98787
a9ec34d98787
使用 kubectl 命令:
kubectl get deployment nginx-app
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
nginx-app 1 1 1 1 2m
kubectl get po -l run = nginx-app
NAME READY STATUS RESTARTS AGE
nginx-app-2883164633-aklf7 1/1 Running 0 2m
kubectl delete deployment nginx-app
deployment "nginx-app" deleted
kubectl get po -l run = nginx-app
# Return nothing
说明: 请注意,我们不直接删除 pod。使用 kubectl 命令,我们要删除拥有该 pod 的 Deployment。如果我们直接删除 pod,Deployment 将会重新创建该 pod。
docker login 在 kubectl 中没有对 docker login 的直接模拟。如果您有兴趣在私有镜像仓库中使用 Kubernetes,请参阅使用私有镜像仓库 。
docker version 如何查看客户端和服务端的版本?查看 kubectl version 。
使用 docker 命令:
Client version: 1.7.0
Client API version: 1.19
Go version (client): go1.4.2
Git commit (client): 0baf609
OS/Arch (client): linux/amd64
Server version: 1.7.0
Server API version: 1.19
Go version (server): go1.4.2
Git commit (server): 0baf609
OS/Arch (server): linux/amd64
使用 kubectl 命令:
Client Version: version.Info{Major:"1", Minor:"6", GitVersion:"v1.6.9+a3d1dfa6f4335", GitCommit:"9b77fed11a9843ce3780f70dd251e92901c43072", GitTreeState:"dirty", BuildDate:"2017-08-29T20:32:58Z", OpenPaasKubernetesVersion:"v1.03.02", GoVersion:"go1.7.5", Compiler:"gc", Platform:"linux/amd64"}
Server Version: version.Info{Major:"1", Minor:"6", GitVersion:"v1.6.9+a3d1dfa6f4335", GitCommit:"9b77fed11a9843ce3780f70dd251e92901c43072", GitTreeState:"dirty", BuildDate:"2017-08-29T20:32:58Z", OpenPaasKubernetesVersion:"v1.03.02", GoVersion:"go1.7.5", Compiler:"gc", Platform:"linux/amd64"}
docker info 如何获取有关环境和配置的各种信息?查看 kubectl cluster-info 。
使用 docker 命令:
Containers: 40
Images: 168
Storage Driver: aufs
Root Dir: /usr/local/google/docker/aufs
Backing Filesystem: extfs
Dirs: 248
Dirperm1 Supported: false
Execution Driver: native-0.2
Logging Driver: json-file
Kernel Version: 3.13.0-53-generic
Operating System: Ubuntu 14.04.2 LTS
CPUs: 12
Total Memory: 31.32 GiB
Name: k8s-is-fun.mtv.corp.google.com
ID: ADUV:GCYR:B3VJ:HMPO:LNPQ:KD5S:YKFQ:76VN:IANZ:7TFV:ZBF4:BYJO
WARNING: No swap limit support
使用 kubectl 命令:
Kubernetes master is running at https://108.59.85.141
KubeDNS is running at https://108.59.85.141/api/v1/namespaces/kube-system/services/kube-dns/proxy
kubernetes-dashboard is running at https://108.59.85.141/api/v1/namespaces/kube-system/services/kubernetes-dashboard/proxy
Grafana is running at https://108.59.85.141/api/v1/namespaces/kube-system/services/monitoring-grafana/proxy
Heapster is running at https://108.59.85.141/api/v1/namespaces/kube-system/services/monitoring-heapster/proxy
InfluxDB is running at https://108.59.85.141/api/v1/namespaces/kube-system/services/monitoring-influxdb/proxy
6.9 - 命令行工具参考 6.9.2 - kubelet 简介 kubelet 是在每个 Node 节点上运行的主要 “节点代理”。它可以使用以下之一向 apiserver 注册:
主机名(hostname);覆盖主机名的参数;某云驱动的特定逻辑。
kubelet 是基于 PodSpec 来工作的。每个 PodSpec 是一个描述 Pod 的 YAML 或 JSON 对象。
kubelet 接受通过各种机制(主要是通过 apiserver)提供的一组 PodSpec,并确保这些
PodSpec 中描述的容器处于运行状态且运行状况良好。
kubelet 不管理不是由 Kubernetes 创建的容器。
除了来自 apiserver 的 PodSpec 之外,还可以通过以下三种方式将容器清单(manifest)提供给 kubelet。
文件(File):利用命令行参数传递路径。kubelet 周期性地监视此路径下的文件是否有更新。
监视周期默认为 20s,且可通过参数进行配置。
HTTP 端点(HTTP endpoint):利用命令行参数指定 HTTP 端点。
此端点的监视周期默认为 20 秒,也可以使用参数进行配置。
HTTP 服务器(HTTP server):kubelet 还可以侦听 HTTP 并响应简单的 API
(目前没有完整规范)来提交新的清单。
kubelet [flags]
选项 --add-dir-header 设置为 true 表示将文件目录添加到日志消息的头部 --address ip 默认值:0.0.0.0 kubelet 用来提供服务的 IP 地址(设置为0.0.0.0 表示使用所有 IPv4 接口,
设置为 :: 表示使用所有 IPv6 接口)。已弃用:应在 --config 所给的
配置文件中进行设置。(进一步了解 ) --allowed-unsafe-sysctls strings 用逗号分隔的字符串序列设置允许使用的非安全的 sysctls 或 sysctl 模式(以 * 结尾) 。
使用此参数时风险自担。已弃用:应在 --config 所给的配置文件中进行设置。
(进一步了解 ). --alsologtostderr 设置为 true 表示将日志输出到文件的同时输出到 stderr --anonymous-auth 默认值:true 设置为 true 表示 kubelet 服务器可以接受匿名请求。未被任何认证组件拒绝的请求将被视为匿名请求。
匿名请求的用户名为 system:anonymous,用户组为 system:unauthenticated。
已弃用:应在 --config 所给的配置文件中进行设置。
(进一步了解 ) --authentication-token-webhook 使用 TokenReview API 对持有者令牌进行身份认证。
已弃用:应在 --config 所给的配置文件中进行设置。
(进一步了解 ) --authentication-token-webhook-cache-ttl duration 默认值:2m0s 对 Webhook 令牌认证组件所返回的响应的缓存时间。
已弃用:应在 --config 所给的配置文件中进行设置。
(进一步了解 ) --authorization-mode string kubelet 服务器的鉴权模式。可选值包括:AlwaysAllow、Webhook。Webhook 模式使用 SubjectAccessReview API 鉴权。
当 --config 参数未被设置时,默认值为 AlwaysAllow,当使用了
--config 时,默认值为 Webhook。
已弃用:应在 --config 所给的配置文件中进行设置。
(进一步了解 ) --authorization-webhook-cache-authorized-ttl duration 默认值:5m0s 对 Webhook 认证组件所返回的 “Authorized(已授权)” 应答的缓存时间。
已弃用:应在 --config 所给的配置文件中进行设置。
(进一步了解 ) --authorization-webhook-cache-unauthorized-ttl duration 默认值:30s 对 Webhook 认证组件所返回的 “Unauthorized(未授权)” 应答的缓存时间。
--config 时,默认值为 Webhook。
已弃用:应在 --config 所给的配置文件中进行设置。
(进一步了解 ) --azure-container-registry-config string 包含 Azure 容器镜像库配置信息的文件的路径。 --bootstrap-kubeconfig string 某 kubeconfig 文件的路径,该文件将用于获取 kubelet 的客户端证书。
如果 --kubeconfig 所指定的文件不存在,则使用引导所用 kubeconfig
从 API 服务器请求客户端证书。成功后,将引用生成的客户端证书和密钥的 kubeconfig
写入 --kubeconfig 所指定的路径。客户端证书和密钥文件将存储在 --cert-dir
所指的目录。 --cert-dir string 默认值:/var/lib/kubelet/pki TLS 证书所在的目录。如果设置了 --tls-cert-file 和 --tls-private-key-file,
则此标志将被忽略。 --cgroup-driver string 默认值:cgroupfs kubelet 用来操作本机 cgroup 时使用的驱动程序。支持的选项包括 cgroupfs
和 systemd。
已弃用:应在 --config 所给的配置文件中进行设置。
(进一步了解 )
/td> --cgroup-root string 默认值:"" 可选的选项,为 Pod 设置根 cgroup。容器运行时会尽可能使用此配置。
默认值 "" 意味着将使用容器运行时的默认设置。
已弃用:应在 --config 所给的配置文件中进行设置。
(进一步了解 ) --cgroups-per-qos 默认值:true 启用创建 QoS cgroup 层次结构。此值为 true 时 kubelet 为 QoS 和 Pod 创建顶级的 cgroup。
已弃用:应在 --config 所给的配置文件中进行设置。
(进一步了解 ) --chaos-chance float 如果此值大于 0.0,则引入随机客户端错误和延迟。用于测试。
已启用:将在未来版本中移除。 --client-ca-file string 如果设置了此参数,则使用对应文件中机构之一检查请求中所携带的客户端证书。
若客户端证书通过身份认证,则其对应身份为其证书中所设置的 CommonName。
已弃用:应在 --config 所给的配置文件中进行设置。
(进一步了解 ) --cloud-config string 云驱动配置文件的路径。空字符串表示没有配置文件。
已弃用:将在 1.23 版本中移除,以便于从 kubelet 中去除云驱动代码。 --cloud-provider string 云服务的提供者。设置为空字符串表示在没有云驱动的情况下运行。
如果设置了此标志,则云驱动负责确定节点的名称(参考云提供商文档以确定是否以及如何使用主机名)。
已弃用:将在 1.23 版本中移除,以便于从 kubelet 中去除云驱动代码。 --cluster-dns strings DNS 服务器的 IP 地址,以逗号分隔。此标志值用于 Pod 中设置了 “dnsPolicy=ClusterFirst”
时为容器提供 DNS 服务。注意:列表中出现的所有 DNS 服务器必须包含相同的记录组,
否则集群中的名称解析可能无法正常工作。至于名称解析过程中会牵涉到哪些 DNS 服务器,
这一点无法保证。
--config 时,默认值为 Webhook。
已弃用:应在 --config 所给的配置文件中进行设置。
(进一步了解 ) --cluster-domain string 集群的域名。如果设置了此值,kubelet 除了将主机的搜索域配置到所有容器之外,还会为其
配置所搜这里指定的域名。
--config 时,默认值为 Webhook。
已弃用:应在 --config 所给的配置文件中进行设置。
(进一步了解 ) --cni-bin-dir string 默认值:/opt/cni/bin <警告:alpha 特性> 此值为以逗号分隔的完整路径列表。
kubelet 将在所指定路径中搜索 CNI 插件的可执行文件。
仅当容器运行环境设置为 docker 时,此特定于 docker 的参数才有效。 --cni-cache-dir string 默认值:/var/lib/cni/cache <警告:alpha 特性> 此值为一个目录的全路径名。CNI 将在其中缓存文件。
仅当容器运行环境设置为 docker 时,此特定于 docker 的参数才有效。 --cni-conf-dir string 默认值:/etc/cni/net.d <警告:alpha 特性> 此值为某目录的全路径名。kubelet 将在其中搜索 CNI 配置文件。
仅当容器运行环境设置为 docker 时,此特定于 docker 的参数才有效。 --config string kubelet 将从此标志所指的文件中加载其初始配置。此路径可以是绝对路径,也可以是相对路径。
相对路径按 kubelet 的当前工作目录起计。省略此参数时 kubelet 会使用内置的默认配置值。
命令行参数会覆盖此文件中的配置。 --container-log-max-files int32 默认值:5 <警告:beta 特性> 设置容器的日志文件个数上限。此值必须不小于 2。
此标志只能与 --container-runtime=remote 标志一起使用。
已弃用:应在 --config 所给的配置文件中进行设置。
(进一步了解 ) --container-log-max-size string 默认值:10Mi <警告:beta 特性> 设置容器日志文件在轮换生成新文件时之前的最大值
(例如,10Mi)。
此标志只能与 --container-runtime=remote 标志一起使用。
已弃用:应在 --config 所给的配置文件中进行设置。
(进一步了解 ) --container-runtime string 默认值:docker 要使用的容器运行时。目前支持 docker、remote。 --container-runtime-endpoint string 默认值:unix:///var/run/dockershim.sock [实验性特性] 远程运行时服务的端点。目前支持 Linux 系统上的 UNIX 套接字和
Windows 系统上的 npipe 和 TCP 端点。例如:
unix:///var/run/dockershim.sock、
npipe:////./pipe/dockershim。 --contention-profiling 当启用了性能分析时,启用锁竞争分析。
已弃用:应在 --config 所给的配置文件中进行设置。
(进一步了解 ) --cpu-cfs-quota 默认值:true 为设置了 CPU 限制的容器启用 CPU CFS 配额保障。
已弃用:应在 --config 所给的配置文件中进行设置。
(进一步了解 ) --cpu-cfs-quota-period duration 默认值:100ms 设置 CPU CFS 配额周期 cpu.cfs_period_us。默认使用 Linux 内核所设置的默认值 。
已弃用:应在 --config 所给的配置文件中进行设置。
(进一步了解 ) --cpu-manager-policy string 默认值:none 要使用的 CPU 管理器策略。可选值包括:none 和 static。
已弃用:应在 --config 所给的配置文件中进行设置。
(进一步了解 ) --cpu-manager-reconcile-period duration 默认值:10s <警告:alpha 特性> 设置 CPU 管理器的调和时间。例如:10s 或者 1m。
如果未设置,默认使用节点状态更新频率。
已弃用:应在 --config 所给的配置文件中进行设置。
(进一步了解 ) --docker-endpoint string 默认值:unix:///var/run/docker.sock 使用这里的端点与 docker 端点通信。
仅当容器运行环境设置为 docker 时,此特定于 docker 的参数才有效。 --dynamic-config-dir string kubelet 使用此目录来保存所下载的配置,跟踪配置运行状况。
如果目录不存在,则 kubelet 创建该目录。此路径可以是绝对路径,也可以是相对路径。
相对路径从 kubelet 的当前工作目录计算。
设置此参数将启用动态 kubelet 配置。必须启用 DynamicKubeletConfig
特性门控之后才能设置此标志;由于此特性为 beta 阶段,对应的特性门控当前默认为
true。 --enable-cadvisor-json-endpoints Default: `false` 启用 cAdvisor JSON 数据的 /spec 和 /stats/* 端点。
已弃用:未来版本将会移除此标志。 --enable-controller-attach-detach 默认值:true 启用 Attach/Detach 控制器来挂接和摘除调度到该节点的卷,同时禁用 kubelet 执行挂接和摘除操作。 --enable-debugging-handlers Default: `true` 启用服务器上用于日志收集和在本地运行容器和命令的端点。
已弃用:应在 --config 所给的配置文件中进行设置。
(进一步了解 ) --enable-server 启用 kubelet 服务器。
已弃用:应在 --config 所给的配置文件中进行设置。
(进一步了解 ) --enforce-node-allocatable strings Default: `pods` 用逗号分隔的列表,包含由 kubelet 强制执行的节点可分配资源级别。
可选配置为:none、pods、system-reserved 和 kube-reserved。
在设置 system-reserved 和 kube-reserved 这两个值时,同时要求设置
--system-reserved-cgroup 和 --kube-reserved-cgroup 这两个参数。
如果设置为 none,则不需要设置其他参数。
参考相关文档 。
已弃用:应在 --config 所给的配置文件中进行设置。
(进一步了解 ) --event-burst int32 默认值:10 事件记录的个数的突发峰值上限,在遵从 --event-qps 阈值约束的前提下
临时允许事件记录达到此数目。仅在 --event-qps 大于 0 时使用。
已弃用:应在 --config 所给的配置文件中进行设置。
(进一步了解 ) --event-qps int32 Default: 5 设置大于 0 的值表示限制每秒可生成的事件数量。设置为 0 表示不限制。
已弃用:应在 --config 所给的配置文件中进行设置。
(进一步了解 ) --eviction-hard string 默认值:imagefs.available<15%,memory.available<100Mi,nodefs.available<10% 触发 Pod 驱逐操作的一组硬性门限(例如:memory.available<1Gi
(内存可用值小于 1 G))设置。在 Linux 节点上,默认值还包括
nodefs.inodesFree<5%。
已弃用:应在 --config 所给的配置文件中进行设置。
(进一步了解 ) --eviction-max-pod-grace-period int32 响应满足软性驱逐阈值(Soft Eviction Threshold)而终止 Pod 时使用的最长宽限期(以秒为单位)。
如果设置为负数,则遵循 Pod 的指定值。
已弃用:应在 --config 所给的配置文件中进行设置。
(进一步了解 ) --eviction-minimum-reclaim mapStringString 当某资源压力过大时,kubelet 将执行 Pod 驱逐操作。
此参数设置软性驱逐操作需要回收的资源的最小数量(例如:imagefs.available=2Gi)。
已弃用:应在 --config 所给的配置文件中进行设置。
(进一步了解 ) --eviction-pressure-transition-period duration 默认值:5m0s kubelet 在驱逐压力状况解除之前的最长等待时间。
已弃用:应在 --config 所给的配置文件中进行设置。
(进一步了解 ) --eviction-soft mapStringString 设置一组驱逐阈值(例如:memory.available<1.5Gi)。
如果在相应的宽限期内达到该阈值,则会触发 Pod 驱逐操作。
已弃用:应在 --config 所给的配置文件中进行设置。
(进一步了解 ) --eviction-soft-grace-period mapStringString 设置一组驱逐宽限期(例如,memory.available=1m30s),对应于触发软性 Pod
驱逐操作之前软性驱逐阈值所需持续的时间长短。
已弃用:应在 --config 所给的配置文件中进行设置。
(进一步了解 ) --exit-on-lock-contention 设置为 true 表示当发生锁文件竞争时 kubelet 可以退出。 --experimental-allocatable-ignore-eviction 默认值:false 设置为 true 表示在计算节点可分配资源数量时忽略硬性逐出阈值设置。
参考
相关文档 。
已启用:将在 1.23 版本中移除。 --experimental-bootstrap-kubeconfig string 已弃用:应使用 --bootstrap-kubeconfig 标志 --experimental-check-node-capabilities-before-mount [实验性特性] 设置为 true 表示 kubelet 在进行挂载卷操作之前要
在本节点上检查所需的组件(如可执行文件等)是否存在。
已弃用:将在 1.23 版本中移除,以便使用 CSI。 --experimental-kernel-memcg-notification 设置为 true 表示 kubelet 将会集成内核的 memcg 通知机制而不是使用轮询机制来
判断是否达到了内存驱逐阈值。
此标志将在 1.23 版本移除。
已弃用:应在 --config 所给的配置文件中进行设置。
(进一步了解 ) --experimental-log-sanitization [试验性功能] 启用此标志之后,kubelet 会避免将标记为敏感的字段(密码、密钥、令牌等)
写入日志中。运行时的日志清理可能会带来相当的计算开销,因此不应该在
产品环境中启用。
已弃用:应在 --config 所给的配置文件中进行设置。
(进一步了解 ) --experimental-mounter-path string 默认值:mount [实验性特性] 卷挂载器(mounter)的可执行文件的路径。设置为空表示使用默认挂载器 mount。
已弃用:将在 1.23 版本移除以支持 CSI。 --fail-swap-on 默认值:true 设置为 true 表示如果主机启用了交换分区,kubelet 将直接失败。
已弃用:应在 --config 所给的配置文件中进行设置。
(进一步了解 ) --feature-gates mapStringBool 用于 alpha 实验性质的特性开关组,每个开关以 key=value 形式表示。当前可用开关包括:
APIListChunking=true|false (BETA - 默认值为 true) APIPriorityAndFairness=true|false (BETA - 默认值为 true) APIResponseCompression=true|false (BETA - 默认值为 true) APIServerIdentity=true|false (ALPHA - 默认值为 false) AllAlpha=true|false (ALPHA - 默认值为 false) AllBeta=true|false (BETA - 默认值为 false) AllowInsecureBackendProxy=true|false (BETA - 默认值为 true) AnyVolumeDataSource=true|false (ALPHA - 默认值为 false) AppArmor=true|false (BETA - 默认值为 true) BalanceAttachedNodeVolumes=true|false (ALPHA - 默认值为 false) BoundServiceAccountTokenVolume=true|false (ALPHA - 默认值为 false) CPUManager=true|false (BETA - 默认值为 true) CRIContainerLogRotation=true|false (BETA - 默认值为 true) CSIInlineVolume=true|false (BETA - 默认值为 true) CSIMigration=true|false (BETA - 默认值为 true) CSIMigrationAWS=true|false (BETA - 默认值为 false) CSIMigrationAWSComplete=true|false (ALPHA - 默认值为 false) CSIMigrationAzureDisk=true|false (BETA - 默认值为 false) CSIMigrationAzureDiskComplete=true|false (ALPHA - 默认值为 false) CSIMigrationAzureFile=true|false (ALPHA - 默认值为 false) CSIMigrationAzureFileComplete=true|false (ALPHA - 默认值为 false) CSIMigrationGCE=true|false (BETA - 默认值为 false) CSIMigrationGCEComplete=true|false (ALPHA - 默认值为 false) CSIMigrationOpenStack=true|false (BETA - 默认值为 false) CSIMigrationOpenStackComplete=true|false (ALPHA - 默认值为 false) CSIMigrationvSphere=true|false (BETA - 默认值为 false) CSIMigrationvSphereComplete=true|false (BETA - 默认值为 false) CSIServiceAccountToken=true|false (ALPHA - 默认值为 false) CSIStorageCapacity=true|false (ALPHA - 默认值为 false) CSIVolumeFSGroupPolicy=true|false (BETA - 默认值为 true) ConfigurableFSGroupPolicy=true|false (BETA - 默认值为 true) CronJobControllerV2=true|false (ALPHA - 默认值为 false) CustomCPUCFSQuotaPeriod=true|false (ALPHA - 默认值为 false) DefaultPodTopologySpread=true|false (BETA - 默认值为 true) DevicePlugins=true|false (BETA - 默认值为 true) DisableAcceleratorUsageMetrics=true|false (BETA - 默认值为 true) DownwardAPIHugePages=true|false (ALPHA - 默认值为 false) DynamicKubeletConfig=true|false (BETA - 默认值为 true) EfficientWatchResumption=true|false (ALPHA - 默认值为 false) EndpointSlice=true|false (BETA - 默认值为 true) EndpointSliceNodeName=true|false (ALPHA - 默认值为 false) EndpointSliceProxying=true|false (BETA - 默认值为 true) EndpointSliceTerminatingCondition=true|false (ALPHA - 默认值为 false) EphemeralContainers=true|false (ALPHA - 默认值为 false) ExpandCSIVolumes=true|false (BETA - 默认值为 true) ExpandInUsePersistentVolumes=true|false (BETA - 默认值为 true) ExpandPersistentVolumes=true|false (BETA - 默认值为 true) ExperimentalHostUserNamespaceDefaulting=true|false (BETA - 默认值为 false) GenericEphemeralVolume=true|false (ALPHA - 默认值为 false) GracefulNodeShutdown=true|false (ALPHA - 默认值为 false) HPAContainerMetrics=true|false (ALPHA - 默认值为 false) HPAScaleToZero=true|false (ALPHA - 默认值为 false) HugePageStorageMediumSize=true|false (BETA - 默认值为 true) IPv6DualStack=true|false (ALPHA - 默认值为 false) ImmutableEphemeralVolumes=true|false (BETA - 默认值为 true) KubeletCredentialProviders=true|false (ALPHA - 默认值为 false) KubeletPodResources=true|false (BETA - 默认值为 true) LegacyNodeRoleBehavior=true|false (BETA - 默认值为 true) LocalStorageCapacityIsolation=true|false (BETA - 默认值为 true) LocalStorageCapacityIsolationFSQuotaMonitoring=true|false (ALPHA - 默认值为 false) MixedProtocolLBService=true|false (ALPHA - 默认值为 false) NodeDisruptionExclusion=true|false (BETA - 默认值为 true) NonPreemptingPriority=true|false (BETA - 默认值为 true) PodDisruptionBudget=true|false (BETA - 默认值为 true) PodOverhead=true|false (BETA - 默认值为 true) ProcMountType=true|false (ALPHA - 默认值为 false) QOSReserved=true|false (ALPHA - 默认值为 false) RemainingItemCount=true|false (BETA - 默认值为 true) RemoveSelfLink=true|false (BETA - 默认值为 true) RootCAConfigMap=true|false (BETA - 默认值为 true) RotateKubeletServerCertificate=true|false (BETA - 默认值为 true) RunAsGroup=true|false (BETA - 默认值为 true) ServerSideApply=true|false (BETA - 默认值为 true) ServiceAccountIssuerDiscovery=true|false (BETA - 默认值为 true) ServiceLBNodePortControl=true|false (ALPHA - 默认值为 false) ServiceNodeExclusion=true|false (BETA - 默认值为 true) ServiceTopology=true|false (ALPHA - 默认值为 false) SetHostnameAsFQDN=true|false (BETA - 默认值为 true) SizeMemoryBackedVolumes=true|false (ALPHA - 默认值为 false) StorageVersionAPI=true|false (ALPHA - 默认值为 false) StorageVersionHash=true|false (BETA - 默认值为 true) Sysctls=true|false (BETA - 默认值为 true) TTLAfterFinished=true|false (ALPHA - 默认值为 false) TopologyManager=true|false (BETA - 默认值为 true) ValidateProxyRedirects=true|false (BETA - 默认值为 true) WarningHeaders=true|false (BETA - 默认值为 true) WinDSR=true|false (ALPHA - 默认值为 false) WinOverlay=true|false (BETA - 默认值为 true) WindowsEndpointSliceProxying=true|false (ALPHA - 默认值为 false) 已弃用:应在 --config 所给的配置文件中进行设置。
(进一步了解 ) --file-check-frequency duration 默认值:20s 检查配置文件中新数据的时间间隔。
已弃用:应在 --config 所给的配置文件中进行设置。
(进一步了解 ) --hairpin-mode string 默认值:promiscuous-bridge 设置 kubelet 执行发夹模式(hairpin)网络地址转译的方式。
该模式允许后端端点对其自身服务的访问能够再次经由负载均衡转发回自身。
可选项包括 “promiscuous-bridge”、“hairpin-veth” 和 “none”。
已弃用:应在 --config 所给的配置文件中进行设置。
(进一步了解 ) --healthz-bind-address ip 默认值:127.0.0.1 用于运行 healthz 服务器的 IP 地址(设置为 0.0.0.0 表示使用所有 IPv4 接口,
设置为 :: 表示使用所有 IPv6 接口。
已弃用:应在 --config 所给的配置文件中进行设置。
(进一步了解 ) --healthz-port int32 默认值:10248 本地 healthz 端点使用的端口(设置为 0 表示禁用)。
已弃用:应在 --config 所给的配置文件中进行设置。
(进一步了解 ) -h, --help kubelet 操作的帮助命令 --hostname-override string 如果为非空,将使用此字符串而不是实际的主机名作为节点标识。如果设置了
--cloud-provider,则云驱动将确定节点的名称
(请查阅云服务商文档以确定是否以及如何使用主机名)。 --housekeeping-interval duration 默认值:10s 清理容器操作的时间间隔。 --http-check-frequency duration 默认值:20s HTTP 服务以获取新数据的时间间隔。
已弃用:应在 --config 所给的配置文件中进行设置。
(进一步了解 ) --image-credential-provider-bin-dir string 指向凭据提供组件可执行文件所在目录的路径。 --image-credential-provider-config string 指向凭据提供插件配置文件所在目录的路径。 --image-gc-high-threshold int32 默认值:85 镜像垃圾回收上限。磁盘使用空间达到该百分比时,镜像垃圾回收将持续工作。
值必须在 [0,100] 范围内。要禁用镜像垃圾回收,请设置为 100。
已弃用:应在 --config 所给的配置文件中进行设置。
(进一步了解 ) --image-gc-low-threshold int32 默认值:80 镜像垃圾回收下限。磁盘使用空间在达到该百分比之前,镜像垃圾回收操作不会运行。
值必须在 [0,100] 范围内,并且不得大于 --image-gc-high-threshold的值。
已弃用:应在 --config 所给的配置文件中进行设置。
(进一步了解 ) --image-pull-progress-deadline duration 默认值:1m0s 如果在该参数值所设置的期限之前没有拉取镜像的进展,镜像拉取操作将被取消。
仅当容器运行环境设置为 docker 时,此特定于 docker 的参数才有效。 --image-service-endpoint string [实验性特性] 远程镜像服务的端点。若未设定则默认情况下使用 --container-runtime-endpoint
的值。目前支持的类型包括在 Linux 系统上的 UNIX 套接字端点和 Windows 系统上的 npipe 和 TCP 端点。
例如:unix:///var/run/dockershim.sock、npipe:////./pipe/dockershim。 --iptables-drop-bit int32 默认值:15 标记数据包将被丢弃的 fwmark 位设置。必须在 [0,31] 范围内。
已弃用:应在 --config 所给的配置文件中进行设置。
(进一步了解 ) --iptables-masquerade-bit int32 默认值:14 标记数据包将进行 SNAT 的 fwmark 空间位设置。必须在 [0,31] 范围内。
请将此参数与 kube-proxy 中的相应参数匹配。
已弃用:应在 --config 所给的配置文件中进行设置。
(进一步了解 ) --keep-terminated-pod-volumes 设置为 true 表示 Pod 终止后仍然保留之前挂载过的卷,常用于调试与卷有关的问题。
已弃用:将未来版本中移除。 --kernel-memcg-notification 若启用,则 kubelet 将与内核中的 memcg 通知机制集成,不再使用轮询的方式来判定
是否 Pod 达到内存驱逐阈值。
已弃用:应在 --config 所给的配置文件中进行设置。
(进一步了解 ) --kube-api-burst int32 默认值:10 每秒发送到 apiserver 的突发请求数量上限。
已弃用:应在 --config 所给的配置文件中进行设置。
(进一步了解 ) --kube-api-content-type string 默认值:application/vnd.kubernetes.protobuf 发送到 apiserver 的请求的内容类型。
已弃用:应在 --config 所给的配置文件中进行设置。
(进一步了解 ) --kube-api-qps int32 默认值:5 与 apiserver 通信的每秒查询个数(QPS)。
已弃用:应在 --config 所给的配置文件中进行设置。
(进一步了解 ) --kube-reserved mapStringString 默认值:<None> kubernetes 系统预留的资源配置,以一组 资源名称=资源数量 格式表示。
(例如:cpu=200m,memory=500Mi,ephemeral-storage=1Gi,pid='100')。
当前支持 cpu、memory 和用于根文件系统的 ephemeral-storage。
请参阅相关文档 获取更多信息。
已弃用:应在 --config 所给的配置文件中进行设置。
(进一步了解 ) --kube-reserved-cgroup string 默认值:"" 给出某个顶层 cgroup 绝对名称,该 cgroup 用于管理通过标志 --kube-reserved
为 kubernetes 组件所预留的计算资源。例如:"/kube-reserved"。
已弃用:应在 --config 所给的配置文件中进行设置。
(进一步了解 ) --kubeconfig string kubeconfig 配置文件的路径,指定如何连接到 API 服务器。
提供 --kubeconfig 将启用 API 服务器模式,而省略 --kubeconfig 将启用独立模式。 --kubelet-cgroups string 用于创建和运行 kubelet 的 cgroup 的绝对名称。
已弃用:应在 --config 所给的配置文件中进行设置。
(进一步了解 ) --lock-file string <警告:alpha 特性> kubelet 使用的锁文件的路径。 --log-backtrace-at traceLocation 默认值::0 形式为 <file>:<N>。
当日志逻辑执行到命中 <file> 的第 <N> 行时,转储调用堆栈。 --log-dir string 如果此值为非空,则在所指定的目录中写入日志文件。 --log-file string 如果此值非空,使用所给字符串作为日志文件名。 --log-file-max-size uint 默认值:1800 设置日志文件的最大值。单位为兆字节(M)。如果值为 0,则表示文件大小无限制。 --log-flush-frequency duration 默认值:5s 两次日志刷新之间的最大秒数(默认值为 5s)。 --logging-format string 默认值:"text" 设置日志文件格式。可以设置的格式有:"text"、"json"。
非默认的格式不会使用以下标志的配置:--add-dir-header, --alsologtostderr,
--log-backtrace-at, --log-dir, --log-file,
--log-file-max-size, --logtostderr, --skip-headers,
--skip-log-headers, --stderrthreshold, --log-flush-frequency。
非默认选项的其它值都应视为 Alpha 特性,将来出现更改时不会额外警告。
已弃用:应在 --config 所给的配置文件中进行设置。
(进一步了解 ) --logtostderr 默认值:true 日志输出到 stderr 而不是文件。 --make-iptables-util-chains 默认值:true 设置为 true 表示 kubelet 将确保 iptables 规则在主机上存在。
已弃用:应在 --config 所给的配置文件中进行设置。
(进一步了解 ) --manifest-url string 用于访问要运行的其他 Pod 规范的 URL。
已弃用:应在 --config 所给的配置文件中进行设置。
(进一步了解 ) --manifest-url-header string 取值为由 HTTP 头部组成的逗号分隔列表,在访问 --manifest-url 所给出的 URL 时使用。
名称相同的多个头部将按所列的顺序添加。该参数可以多次使用。例如:
--manifest-url-header 'a:hello,b:again,c:world' --manifest-url-header 'b:beautiful'。
已弃用:应在 --config 所给的配置文件中进行设置。
(进一步了解 ) --master-service-namespace string 默认值:default kubelet 向 Pod 注入 Kubernetes 主控服务信息时使用的命名空间。
已弃用:此标志将在未来的版本中删除。 --max-open-files int 默认值:1000000 kubelet 进程可以打开的最大文件数量。
已弃用:应在 --config 所给的配置文件中进行设置。
(进一步了解 ) --max-pods int32 默认值:110 此 kubelet 能运行的 Pod 最大数量。
已弃用:应在 --config 所给的配置文件中进行设置。
(进一步了解 ) --maximum-dead-containers int32 默认值:-1 设置全局可保留的已停止容器实例个数上限。
每个实例会占用一些磁盘空间。要禁用,请设置为负数。
已弃用:应在 --config 所给的配置文件中进行设置。
(进一步了解 ) --maximum-dead-containers-per-container int32 默认值:1 每个已停止容器可以保留的的最大实例数量。每个容器占用一些磁盘空间。
已弃用:应在 --config 所给的配置文件中进行设置。
(进一步了解 ) --minimum-container-ttl-duration duration 已结束的容器在被垃圾回收清理之前的最少存活时间。
例如:300ms、10s 或者 2h45m。
已弃用:请改用 --eviction-hard 或者 --eviction-soft。
此标志将在未来的版本中删除。 --minimum-image-ttl-duration duration 默认值:2m0s 不再使用的镜像在被垃圾回收清理之前的最少存活时间。
例如:300ms、10s 或者 2h45m。
已弃用:应在 --config 所给的配置文件中进行设置。
(进一步了解 ) --network-plugin string <警告:alpha 特性> 设置 kubelet/Pod 生命周期中各种事件调用的网络插件的名称。
仅当容器运行环境设置为 docker 时,此特定于 docker 的参数才有效。 --network-plugin-mtu int32 <警告:alpha 特性> 传递给网络插件的 MTU 值,将覆盖默认值。
设置为 0 则使用默认的 MTU 1460。仅当容器运行环境设置为 docker 时,
此特定于 docker 的参数才有效。 --node-ip string 节点的 IP 地址。如果设置,kubelet 将使用该 IP 地址作为节点的 IP 地址。 --node-labels mapStringString <警告:alpha 特性> kubelet 在集群中注册本节点时设置的标签。标签以
key=value 的格式表示,多个标签以逗号分隔。名字空间 kubernetes.io
中的标签必须以 kubelet.kubernetes.io 或 node.kubernetes.io 为前缀,
或者在以下明确允许范围内:
beta.kubernetes.io/arch, beta.kubernetes.io/instance-type,
beta.kubernetes.io/os, failure-domain.beta.kubernetes.io/region,
failure-domain.beta.kubernetes.io/zone, kubernetes.io/arch,
kubernetes.io/hostname, kubernetes.io/os,
node.kubernetes.io/instance-type, topology.kubernetes.io/region,
topology.kubernetes.io/zone。 --node-status-max-images int32 默认值:50 在 node.status.images 中可以报告的最大镜像数量。如果指定为 -1,则不设上限。
已弃用:应在 --config 所给的配置文件中进行设置。
(进一步了解 ) --node-status-update-frequency duration 默认值:10s 指定 kubelet 向主控节点汇报节点状态的时间间隔。注意:更改此常量时请务必谨慎,
它必须与节点控制器中的 nodeMonitorGracePeriod 一起使用。
已弃用:应在 --config 所给的配置文件中进行设置。
(进一步了解 ) --non-masquerade-cidr string 默认值:10.0.0.0/8 kubelet 向该 IP 段之外的 IP 地址发送的流量将使用 IP 伪装技术。
设置为 0.0.0.0/0 则不使用伪装。
已弃用:应在 --config 所给的配置文件中进行设置。
(进一步了解 ) --one-output 如果设置此标志为 true,则仅将日志写入其原来的严重性级别中,
而不是同时将其写入更低严重性级别中。 --oom-score-adj int32 默认值:-999 kubelet 进程的 oom-score-adj 参数值。有效范围为 [-1000,1000]。
已弃用:应在 --config 所给的配置文件中进行设置。
(进一步了解 ) --pod-cidr string 用于给 Pod 分配 IP 地址的 CIDR 地址池,仅在独立运行模式下使用。
在集群模式下,CIDR 设置是从主服务器获取的。对于 IPv6,分配的 IP 的最大数量为 65536。
已弃用:应在 --config 所给的配置文件中进行设置。
(进一步了解 ) --pod-infra-container-image string 默认值:k8s.gcr.io/pause:3.2 指定基础设施镜像,Pod 内所有容器与其共享网络和 IPC 命名空间。
仅当容器运行环境设置为 docker 时,此特定于 docker 的参数才有效。 --pod-manifest-path string 设置包含要运行的静态 Pod 的文件的路径,或单个静态 Pod 文件的路径。以点(.)
开头的文件将被忽略。
已弃用:应在 --config 所给的配置文件中进行设置。
(进一步了解 ) --pod-max-pids int 默认值:-1 设置每个 Pod 中的最大进程数目。如果为 -1,则 kubelet 使用节点可分配的 PID 容量作为默认值。
已弃用:应在 --config 所给的配置文件中进行设置。
(进一步了解 ) --pods-per-core int32 kubelet 在每个处理器核上可运行的 Pod 数量。此 kubelet 上的 Pod 总数不能超过
--max-pods 标志值。因此,如果此计算结果导致在 kubelet
上允许更多数量的 Pod,则使用 --max-pods 值。值为 0 表示不作限制。
已弃用:应在 --config 所给的配置文件中进行设置。
(进一步了解 ) --port int32 默认值:10250 kubelet 服务监听的本机端口号。
已弃用:应在 --config 所给的配置文件中进行设置。
(进一步了解 ) --protect-kernel-defaults 设置 kubelet 的默认内核调整行为。如果已设置该参数,当任何内核可调参数与
kubelet 默认值不同时,kubelet 都会出错。
已弃用:应在 --config 所给的配置文件中进行设置。
(进一步了解 ) --provider-id string 设置主机数据库(即,云驱动)中用来标识节点的唯一标识。
已弃用:应在 --config 所给的配置文件中进行设置。
(进一步了解 ) --qos-reserved mapStringString <警告:alpha 特性> 设置在指定的 QoS 级别预留的 Pod 资源请求,以一组
"资源名称=百分比" 的形式进行设置,例如 memory=50%。
当前仅支持内存(memory)。要求启用 QOSReserved 特性门控。
已弃用:应在 --config 所给的配置文件中进行设置。
(进一步了解 ) --read-only-port int32 默认值:10255 kubelet 可以在没有身份验证/鉴权的情况下提供只读服务的端口(设置为 0 表示禁用)。
已弃用:应在 --config 所给的配置文件中进行设置。
(进一步了解 ) --really-crash-for-testing 设置为 true 表示发生失效时立即崩溃。仅用于测试。
已弃用:将在未来版本中移除。 --redirect-container-streaming 启用容器流数据重定向。如果设置为 false,则 kubelet 将在 apiserver 和容器运行时
之间转发容器流数据;如果设置为 true,则 kubelet 将返回指向 apiserver 的 HTTP 重定向信息,
而 apiserver 将直接访问容器运行时。代理方法更安全,但会带来一些开销。
重定向方法性能更高,但安全性较低,因为 apiserver 和容器运行时之间的连接可能未通过身份验证。 已弃用:容器流数据重定向会在 v1.20 中从 kubelet 中移除,此标志会在 v1.22
中移除。
相关信息可参见改进说明 。 --register-node 默认值:true 将本节点注册到 API 服务器。如果未提供 --kubeconfig 标志设置,
则此参数无关紧要,因为 kubelet 将没有要注册的 API 服务器。 --register-schedulable 默认值:true 注册本节点为可调度的节点。当 --register-node标志为 false 时此设置无效。
已弃用:此参数将在未来的版本中删除。 --register-with-taints mapStringString 设置本节点的污点标记,格式为 <key>=<value>:<effect>,
以逗号分隔。当 --register-node 为 false 时此标志无效。
已弃用:将在未来版本中移除。 --registry-burst int32 默认值:10 设置突发性镜像拉取的个数上限,在不超过 --registration-qps 设置值的前提下
暂时允许此参数所给的镜像拉取个数。仅在 --registry-qps 大于 0 时使用。
已弃用:应在 --config 所给的配置文件中进行设置。
(进一步了解 ) --registry-qps int32 Default: 5 如此值大于 0,可用来限制镜像仓库的 QPS 上限。设置为 0,表示不受限制。
已弃用:应在 --config 所给的配置文件中进行设置。
(进一步了解 ) --reserved-cpus string 用逗号分隔的一组 CPU 或 CPU 范围列表,给出为系统和 Kubernetes 保留使用的 CPU。
此列表所给出的设置优先于通过 --system-reserved 和
--kube-reskube-reserved 所保留的 CPU 个数配置。
已弃用:应在 --config 所给的配置文件中进行设置。
(进一步了解 ) --resolv-conf string 默认值:/etc/resolv.conf 名字解析服务的配置文件名,用作容器 DNS 解析配置的基础。
已弃用:应在 --config 所给的配置文件中进行设置。
(进一步了解 ) --root-dir string 默认值:/var/lib/kubelet 设置用于管理 kubelet 文件的根目录(例如挂载卷的相关文件等)。 --rotate-certificates <警告:Beta 特性> 设置当客户端证书即将过期时 kubelet 自动从
kube-apiserver 请求新的证书进行轮换。
已弃用:应在 --config 所给的配置文件中进行设置。
(进一步了解 ) --rotate-server-certificates 当 kubelet 的服务证书即将过期时自动从 kube-apiserver 请求新的证书进行轮换。
要求启用 RotateKubeletServerCertificate 特性门控,以及对提交的
CertificateSigningRequest 对象进行批复(Approve)操作。
已弃用:应在 --config 所给的配置文件中进行设置。
(进一步了解 ) --runonce 设置为 true 表示从本地清单或远程 URL 创建完 Pod 后立即退出 kubelet 进程。
与 --enable-server 标志互斥。
已弃用:应在 --config 所给的配置文件中进行设置。
(进一步了解 ) --runtime-cgroups string 设置用于创建和运行容器运行时的 cgroup 的绝对名称。 --runtime-request-timeout duration 默认值:2m0s 设置除了长时间运行的请求(包括 pull、logs、exec
和 attach 等操作)之外的其他运行时请求的超时时间。
到达超时时间时,请求会被取消,抛出一个错误并会等待重试。
已弃用:应在 --config 所给的配置文件中进行设置。
(进一步了解 ) --seccomp-profile-root string 默认值:/var/lib/kubelet/seccomp <警告:alpha 特性> seccomp 配置文件目录。
已弃用:将在 1.23 版本中移除,以使用 <root-dir>/seccomp 目录。 --serialize-image-pulls 默认值:true 逐一拉取镜像。建议 *不要* 在 docker 守护进程版本低于 1.9 或启用了 Aufs 存储后端的节点上
更改默认值。
已弃用:应在 --config 所给的配置文件中进行设置。
(进一步了解 ) --skip-headers 设置为 true 时在日志消息中去掉标头前缀。 --skip-log-headers 设置为 true,打开日志文件时去掉标头。 --stderrthreshold int 默认值:2 设置严重程度达到或超过此阈值的日志输出到标准错误输出。 --streaming-connection-idle-timeout duration 默认值:4h0m0s 设置流连接在自动关闭之前可以空闲的最长时间。0 表示没有超时限制。
例如:5m。
已弃用:应在 --config 所给的配置文件中进行设置。
(进一步了解 ) --sync-frequency duration 默认值:1m0s 在运行中的容器与其配置之间执行同步操作的最长时间间隔。
已弃用:应在 --config 所给的配置文件中进行设置。
(进一步了解 ) --system-cgroups / 此标志值为一个 cgroup 的绝对名称,用于所有尚未放置在根目录下某 cgroup 内的非内核进程。
空值表示不指定 cgroup。回滚该参数需要重启机器。
已弃用:应在 --config 所给的配置文件中进行设置。
(进一步了解 ) --system-reserved mapStringString 默认值:无 系统预留的资源配置,以一组 资源名称=资源数量 的格式表示,
(例如:cpu=200m,memory=500Mi,ephemeral-storage=1Gi,pid='100')。
目前仅支持 cpu 和 memory 的设置。
更多细节可参考
相关文档 。
已弃用:应在 --config 所给的配置文件中进行设置。
(进一步了解 ) --system-reserved-cgroup string 默认值:"" 此标志给出一个顶层 cgroup 绝对名称,该 cgroup 用于管理非 kubernetes 组件,
这些组件的计算资源通过 --system-reserved 标志进行预留。
例如 "/system-reserved"。
已弃用:应在 --config 所给的配置文件中进行设置。
(进一步了解 ) --tls-cert-file string 包含 x509 证书的文件路径,用于 HTTPS 认证。
如果有中间证书,则中间证书要串接在在服务器证书之后。
如果未提供 --tls-cert-file 和 --tls-private-key-file,
kubelet 会为公开地址生成自签名证书和密钥,并将其保存到通过
--cert-dir 指定的目录中。
已弃用:应在 --config 所给的配置文件中进行设置。
(进一步了解 ) --tls-cipher-suites string 服务器端加密算法列表,以逗号分隔。如果不设置,则使用 Go 语言加密包的默认算法列表。 可选加密算法包括:TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_RSA_WITH_RC4_128_SHA,TLS_RSA_WITH_3DES_EDE_CBC_SHA,TLS_RSA_WITH_AES_128_CBC_SHA,TLS_RSA_WITH_AES_128_CBC_SHA256,TLS_RSA_WITH_AES_128_GCM_SHA256,TLS_RSA_WITH_AES_256_CBC_SHA,TLS_RSA_WITH_AES_256_GCM_SHA384,TLS_RSA_WITH_RC4_128_SHA 已弃用:应在 --config 所给的配置文件中进行设置。
(进一步了解 ) --tls-min-version string 设置支持的最小 TLS 版本号,可选的版本号包括:VersionTLS10、
VersionTLS11、VersionTLS12 和 VersionTLS13。
已弃用:应在 --config 所给的配置文件中进行设置。
(进一步了解 ) --tls-private-key-file string 包含与 --tls-cert-file 对应的 x509 私钥文件路径。
已弃用:应在 --config 所给的配置文件中进行设置。
(进一步了解 ) --topology-manager-policy string 默认值:none 设置拓扑管理策略(Topology Manager policy)。可选值包括:none、
best-effort、restricted 和 single-numa-node。
已弃用:应在 --config 所给的配置文件中进行设置。
(进一步了解 ) --topology-manager-scope string 默认值:container 拓扑提示信息使用范围。拓扑管理器从提示提供者(Hints Providers)处收集提示信息,
并将其应用到所定义的范围以确保 Pod 准入。
可选值包括:container(默认)、pod。
已弃用:应在 --config 所给的配置文件中进行设置。
(进一步了解 ) -v, --v Level 设置 kubelet 日志级别详细程度的数值。 --version version[=true] 打印 kubelet 版本信息并退出。 --vmodule moduleSpec 以逗号分隔的 pattern=N 设置列表,用于文件过滤的日志记录 --volume-plugin-dir string 默认值:/usr/libexec/kubernetes/kubelet-plugins/volume/exec/ 用来搜索第三方存储卷插件的目录。
已弃用:应在 --config 所给的配置文件中进行设置。
(进一步了解 ) --volume-stats-agg-period duration 默认值:1m0s 指定 kubelet 计算和缓存所有 Pod 和卷的磁盘用量总值的时间间隔。要禁用磁盘用量计算,
请设置为 0。
已弃用:应在 --config 所给的配置文件中进行设置。
(进一步了解 )
6.9.3 - kube-apiserver 简介 Kubernetes API 服务器验证并配置 API 对象的数据,
这些对象包括 pods、services、replicationcontrollers 等。
API 服务器为 REST 操作提供服务,并为集群的共享状态提供前端,
所有其他组件都通过该前端进行交互。
kube-apiserver [flags]
选项 --add-dir-header 如果为 true,则将文件目录添加到日志消息的标题中 --admission-control-config-file string 包含准入控制配置的文件。 --advertise-address ip 向集群成员通知 apiserver 消息的 IP 地址。
这个地址必须能够被集群中其他成员访问。
如果 IP 地址为空,将会使用 --bind-address,
如果未指定 --bind-address,将会使用主机的默认接口地址。 --allow-privileged 如果为 true, 将允许特权容器。[默认值=false] --alsologtostderr 在向文件输出日志的同时,也将日志写到标准输出。 --anonymous-auth 默认值:true 启用到 API server 的安全端口的匿名请求。
未被其他认证方法拒绝的请求被当做匿名请求。
匿名请求的用户名为 system:anonymous,
用户组名为 system:unauthenticated。 --api-audiences stringSlice API 的标识符。
服务帐户令牌验证者将验证针对 API 使用的令牌是否已绑定到这些受众中的至少一个。
如果配置了 --service-account-issuer 标志,但未配置此标志,
则此字段默认为包含发行者 URL 的单个元素列表。 --apiserver-count int 默认值:1 集群中运行的 apiserver 数量,必须为正数。
(在启用 --endpoint-reconciler-type=master-count 时使用。) --audit-log-batch-buffer-size int 默认值:10000 批处理和写入之前用于存储事件的缓冲区大小。
仅在批处理模式下使用。 --audit-log-batch-max-size int 默认值:1 批处理的最大大小。 仅在批处理模式下使用。 --audit-log-batch-max-wait duration 强制写入尚未达到最大大小的批处理之前要等待的时间。
仅在批处理模式下使用。 --audit-log-batch-throttle-burst int 如果之前未使用 ThrottleQPS,则同时发送的最大请求数。
仅在批处理模式下使用。 --audit-log-batch-throttle-enable 是否启用了批量限制。
仅在批处理模式下使用。 --audit-log-batch-throttle-qps float32 每秒的最大平均批处理数。
仅在批处理模式下使用。 --audit-log-compress 若设置了此标志,则轮换的日志文件会使用 gzip 压缩。 --audit-log-format string 默认值:"json" 所保存的审计格式。
"legacy" 表示每行一个事件的文本格式。"json" 表示结构化的 JSON 格式。
已知格式为 legacy,json。 --audit-log-maxage int 根据文件名中编码的时间戳保留旧审计日志文件的最大天数。 --audit-log-maxbackup int 保留的旧审计日志文件的最大数量。 --audit-log-maxsize int 轮换之前,审计日志文件的最大大小(以兆字节为单位)。 --audit-log-mode string 默认值:"blocking" 发送审计事件的策略。
阻塞(blocking)表示发送事件应阻止服务器响应。
批处理导致后端异步缓冲和写入事件。
已知的模式是批处理(batch),阻塞(blocking),严格阻塞(blocking-strict)。 --audit-log-path string 如果设置,则所有到达 apiserver 的请求都将记录到该文件中。
"-" 表示标准输出。 --audit-log-truncate-enabled 是否启用事件和批次截断。 --audit-log-truncate-max-batch-size int 默认值:10485760 发送到下层后端的批次的最大数据量。
实际的序列化大小可能会增加数百个字节。
如果一个批次超出此限制,则将其分成几个较小的批次。 --audit-log-truncate-max-event-size int 默认值:102400 发送到下层后端的批次的最大数据量。
如果事件的大小大于此数字,则将删除第一个请求和响应,
并且没有减小足够大的程度,则将丢弃事件。 --audit-log-version string 默认值:"audit.k8s.io/v1" 用于序列化写入日志的审计事件的 API 组和版本。 --audit-policy-file string 定义审计策略配置的文件的路径。 --audit-webhook-batch-buffer-size int 默认值:10000 划分批次和写入之前用于存储事件的缓冲区大小。
仅在批处理模式下使用。 --audit-webhook-batch-max-size int 默认值:400 批次的最大大小。
仅在批处理模式下使用。 --audit-webhook-batch-max-wait duration 默认值:30s 强制写入尚未达到最大大小的批处理之前要等待的时间。
仅在批处理模式下使用。 --audit-webhook-batch-throttle-burst int 默认值:15 如果之前未使用 ThrottleQPS,则同时发送的最大请求数。
仅在批处理模式下使用。 --audit-webhook-batch-throttle-enable 默认值:true 是否启用了批量限制。
仅在批处理模式下使用。 --audit-webhook-batch-throttle-qps float32 默认值:10 每秒的最大平均批次数。
仅在批处理模式下使用。 --audit-webhook-config-file string 定义审计 webhook 配置的 kubeconfig 格式文件的路径。 --audit-webhook-initial-backoff duration 默认值:10s 重试第一个失败的请求之前要等待的时间。 --audit-webhook-mode string 默认值:"batch" 发送审计事件的策略。
阻止(Blocking)表示发送事件应阻止服务器响应。
批处理导致后端异步缓冲和写入事件。
已知的模式是批处理(batch),阻塞(blocking),严格阻塞(blocking-strict)。 --audit-webhook-truncate-enabled 是否启用事件和批处理截断。 --audit-webhook-truncate-max-batch-size int 默认值:10485760 发送到下层后端的批次的最大数据量。
实际的序列化大小可能会增加数百个字节。
如果一个批次超出此限制,则将其分成几个较小的批次。 --audit-webhook-truncate-max-event-size int 默认值:102400 发送到下层后端的批次的最大数据量。
如果事件的大小大于此数字,则将删除第一个请求和响应,
并且如果事件和事件的大小没有足够减小,则将丢弃事件。 --audit-webhook-version string 默认值:"audit.k8s.io/v1" 用于序列化写入 Webhook 的审计事件的 API 组和版本。 --authentication-token-webhook-cache-ttl duration 默认值:2m0s 来自 Webhook 令牌身份验证器的缓存响应的持续时间。 --authentication-token-webhook-config-file string 包含 Webhook 配置的文件,用于以 kubeconfig 格式进行令牌认证。
API 服务器将查询远程服务,以对持有者令牌进行身份验证。 --authentication-token-webhook-version string 默认值:"v1beta1" 与 Webhook 之间交换 authentication.k8s.io TokenReview 时使用的 API 版本。 --authorization-mode stringSlice 默认值:[AlwaysAllow] 在安全端口上进行鉴权的插件的顺序列表。
逗号分隔的列表:AlwaysAllow,AlwaysDeny,ABAC,Webhook,RBAC,Node。 --authorization-policy-file string 包含安全策略的文件,其内容为分行 JSON 格式,
在安全端口上与 --authorization-mode=ABAC 一起使用。 --authorization-webhook-cache-authorized-ttl duration 默认值:5m0s 缓存来自 Webhook 鉴权组件的 “授权(authorized)” 响应的持续时间。 --authorization-webhook-cache-unauthorized-ttl duration 默认值:30s 缓存来自 Webhook 鉴权模块的 “未授权(unauthorized)” 响应的持续时间。 --authorization-webhook-config-file string 包含 Webhook 配置的文件,其格式为 kubeconfig,
与 --authorization-mode=Webhook 一起使用。
API 服务器将查询远程服务,以对 API 服务器的安全端口的访问执行鉴权。 --authorization-webhook-version string 默认值:"v1beta1" 与 Webhook 之间交换 authorization.k8s.io SubjectAccessReview 时使用的 API 版本。 --azure-container-registry-config string 包含 Azure 容器仓库配置信息的文件的路径。 --bind-address ip 默认值:0.0.0.0 监听 --secure-port 端口的 IP 地址。
集群的其余部分以及 CLI/web 客户端必须可以访问关联的接口。
如果为空白或未指定地址(0.0.0.0 或 ::),则将使用所有接口。 --cert-dir string 默认值:"/var/run/kubernetes" TLS 证书所在的目录。
如果提供了 --tls-cert-file 和 --tls-private-key-file,则将忽略此标志。 --client-ca-file string 如果已设置,则使用与客户端证书的 CommonName 对应的标识对任何出示由
client-ca 文件中的授权机构之一签名的客户端证书的请求进行身份验证。 --cloud-config string 云厂商配置文件的路径。
空字符串表示无配置文件。 --cloud-provider string 云服务提供商。
空字符串表示没有云厂商。 --cloud-provider-gce-l7lb-src-cidrs cidrs 默认值:130.211.0.0/22,35.191.0.0/16 在 GCE 防火墙中打开 CIDR,以进行 L7 LB 流量代理和运行状况检查 --contention-profiling 如果启用了性能分析,则启用锁争用性能分析 --cors-allowed-origins stringSlice CORS 允许的来源清单,以逗号分隔。
允许的来源可以是支持子域匹配的正则表达式。
如果此列表为空,则不会启用 CORS。 --default-not-ready-toleration-seconds int 默认值:300 标明 notReady:NoExecute 的 tolerationSeconds,
默认情况下将其添加到尚未具有此容忍度的每个 pod 中。 --default-unreachable-toleration-seconds int 默认值:300 标明 unreachable:NoExecute 的 tolerationSeconds,
默认情况下将其添加到尚未具有此容忍度的每个 pod 中。 --default-watch-cache-size int 默认值:100 默认监听(watch)缓存大小。
如果为零,则将为没有设置默认监视大小的资源禁用监视缓存。 --delete-collection-workers int 默认值:1 为 DeleteCollection 调用而产生的工作程序数。
这些用于加速名字空间清理。 --disable-admission-plugins stringSlice 尽管位于默认启用的插件列表中(NamespaceLifecycle、LimitRanger、ServiceAccount、TaintNodesByCondition、Priority、DefaultTolerationSeconds、DefaultStorageClass、StorageObjectInUseProtection、PersistentVolumeClaimResize、RuntimeClass、CertificateApproval、CertificateSigning、CertificateSubjectRestriction、DefaultIngressClass、MutatingAdmissionWebhook、ValidatingAdmissionWebhook、ResourceQuota)仍须被禁用的插件。 取值为逗号分隔的准入插件列表:AlwaysAdmit、AlwaysDeny、AlwaysPullImages、CertificateApproval、CertificateSigning、CertificateSubjectRestriction、DefaultIngressClass、DefaultStorageClass、DefaultTolerationSeconds、DenyEscalatingExec、DenyExecOnPrivileged、EventRateLimit、ExtendedResourceToleration、ImagePolicyWebhook、LimitPodHardAntiAffinityTopology、LimitRanger、MutatingAdmissionWebhook、NamespaceAutoProvision、NamespaceExists、NamespaceLifecycle、NodeRestriction、OwnerReferencesPermissionEnforcement、PersistentVolumeClaimResize、PersistentVolumeLabel、PodNodeSelector、PodSecurityPolicy、PodTolerationRestriction、Priority、ResourceQuota、RuntimeClass、SecurityContextDeny、ServiceAccount、StorageObjectInUseProtection、TaintNodesByCondition、ValidatingAdmissionWebhook。 该标志中插件的顺序无关紧要。 --egress-selector-config-file string 带有 apiserver 出站选择器配置的文件。 --enable-admission-plugins stringSlice 除了默认启用的插件(NamespaceLifecycle、LimitRanger、ServiceAccount、TaintNodesByCondition、Priority、DefaultTolerationSeconds、DefaultStorageClass、StorageObjectInUseProtection、PersistentVolumeClaimResize、RuntimeClass、CertificateApproval、CertificateSigning、CertificateSubjectRestriction、DefaultIngressClass、MutatingAdmissionWebhook、ValidatingAdmissionWebhook、ResourceQuota)之外要启用的插件取值为逗号分隔的准入插件列表:AlwaysAdmit、AlwaysDeny、AlwaysPullImages、CertificateApproval、CertificateSigning、CertificateSubjectRestriction、DefaultIngressClass、DefaultStorageClass、DefaultTolerationSeconds、DenyEscalatingExec、DenyExecOnPrivileged、EventRateLimit、ExtendedResourceToleration、ImagePolicyWebhook、LimitPodHardAntiAffinityTopology、LimitRanger、MutatingAdmissionWebhook、NamespaceAutoProvision、NamespaceExists、NamespaceLifecycle、NodeRestriction、OwnerReferencesPermissionEnforcement、PersistentVolumeClaimResize、PersistentVolumeLabel、PodNodeSelector、PodSecurityPolicy、PodTolerationRestriction、Priority、ResourceQuota、RuntimeClass、SecurityContextDeny、ServiceAccount、StorageObjectInUseProtection、TaintNodesByCondition、ValidatingAdmissionWebhook 该标志中插件的顺序无关紧要。 --enable-aggregator-routing 允许聚合器将请求路由到端点 IP 而非集群 IP。 --enable-bootstrap-token-auth 启用以允许将 "kube-system" 名字空间中类型为 "bootstrap.kubernetes.io/token"
的 Secret 用于 TLS 引导身份验证。 --enable-garbage-collector 默认值:true 启用通用垃圾收集器。
必须与 kube-controller-manager 的相应标志同步。 --enable-priority-and-fairness 默认值:true 如果为 true 且启用了 APIPriorityAndFairness 特性门控,
请使用增强的处理程序替换 max-in-flight 处理程序,
以便根据优先级和公平性完成排队和调度。 --encryption-provider-config string 包含加密提供程序配置信息的文件,用在 etcd 中所存储的 Secret 上。 --endpoint-reconciler-type string 默认值:"lease" 使用端点协调器(master-count, lease, none) --etcd-cafile string 用于保护 etcd 通信的 SSL 证书颁发机构文件。 --etcd-certfile string 用于保护 etcd 通信的 SSL 证书文件。 --etcd-compaction-interval duration 默认值:5m0s 压缩请求的间隔。
如果为0,则禁用来自 apiserver 的压缩请求。 --etcd-count-metric-poll-period duration 默认值:1m0s 针对每种类型的资源数量轮询 etcd 的频率。
0 禁用度量值收集。 --etcd-db-metric-poll-interval duration 默认值:30s 轮询 etcd 和更新度量值的请求间隔。
0 禁用度量值收集 --etcd-healthcheck-timeout duration
检查 etcd 健康状况时使用的超时时长。 --etcd-keyfile string 用于保护 etcd 通信的 SSL 密钥文件。 --etcd-prefix string 默认值:"/registry" 要在 etcd 中所有资源路径之前添加的前缀。 --etcd-servers stringSlice 要连接的 etcd 服务器列表(scheme://ip:port),以逗号分隔。 --etcd-servers-overrides stringSlice etcd 服务器针对每个资源的重载设置,以逗号分隔。
单个替代格式:组/资源#服务器(group/resource#servers),其中服务器是 URL,以分号分隔。 --event-ttl duration 默认值:1h0m0s 事件的保留时长。 --experimental-logging-sanitization [试验性功能] 启用此标志时,被标记为敏感的字段(密码、密钥、令牌)都不会被日志输出。 运行时的日志清理可能会引入相当程度的计算开销,因此不应该在产品环境中启用。 --external-hostname string 为此主机生成外部化 UR L时要使用的主机名(例如 Swagger API 文档或 OpenID 发现)。 --feature-gates mapStringBool 一组 key=value 对,用来描述测试性/试验性功能的特性门控。可选项有: APIListChunking=true|false (BETA - 默认值=true) APIPriorityAndFairness=true|false (BETA - 默认值=true) APIResponseCompression=true|false (BETA - 默认值=true) APIServerIdentity=true|false (ALPHA - 默认值=false) AllAlpha=true|false (ALPHA - 默认值=false) AllBeta=true|false (BETA - 默认值=false) AllowInsecureBackendProxy=true|false (BETA - 默认值=true) AnyVolumeDataSource=true|false (ALPHA - 默认值=false) AppArmor=true|false (BETA - 默认值=true) BalanceAttachedNodeVolumes=true|false (ALPHA - 默认值=false) BoundServiceAccountTokenVolume=true|false (ALPHA - 默认值=false) CPUManager=true|false (BETA - 默认值=true) CRIContainerLogRotation=true|false (BETA - 默认值=true) CSIInlineVolume=true|false (BETA - 默认值=true) CSIMigration=true|false (BETA - 默认值=true) CSIMigrationAWS=true|false (BETA - 默认值=false) CSIMigrationAWSComplete=true|false (ALPHA - 默认值=false) CSIMigrationAzureDisk=true|false (BETA - 默认值=false) CSIMigrationAzureDiskComplete=true|false (ALPHA - 默认值=false) CSIMigrationAzureFile=true|false (ALPHA - 默认值=false) CSIMigrationAzureFileComplete=true|false (ALPHA - 默认值=false) CSIMigrationGCE=true|false (BETA - 默认值=false) CSIMigrationGCEComplete=true|false (ALPHA - 默认值=false) CSIMigrationOpenStack=true|false (BETA - 默认值=false) CSIMigrationOpenStackComplete=true|false (ALPHA - 默认值=false) CSIMigrationvSphere=true|false (BETA - 默认值=false) CSIMigrationvSphereComplete=true|false (BETA - 默认值=false) CSIServiceAccountToken=true|false (ALPHA - 默认值=false) CSIStorageCapacity=true|false (ALPHA - 默认值=false) CSIVolumeFSGroupPolicy=true|false (BETA - 默认值=true) ConfigurableFSGroupPolicy=true|false (BETA - 默认值=true) CronJobControllerV2=true|false (ALPHA - 默认值=false) CustomCPUCFSQuotaPeriod=true|false (ALPHA - 默认值=false) DefaultPodTopologySpread=true|false (BETA - 默认值=true) DevicePlugins=true|false (BETA - 默认值=true) DisableAcceleratorUsageMetrics=true|false (BETA - 默认值=true) DownwardAPIHugePages=true|false (ALPHA - default=false) DynamicKubeletConfig=true|false (BETA - 默认值=true) EfficientWatchResumption=true|false (ALPHA - 默认值=false) EndpointSlice=true|false (BETA - 默认值=true) EndpointSliceNodeName=true|false (ALPHA - 默认值=false) EndpointSliceProxying=true|false (BETA - 默认值=true) EndpointSliceTerminatingCondition=true|false (ALPHA - 默认值=false) EphemeralContainers=true|false (ALPHA - 默认值=false) ExpandCSIVolumes=true|false (BETA - 默认值=true) ExpandInUsePersistentVolumes=true|false (BETA - 默认值=true) ExpandPersistentVolumes=true|false (BETA - 默认值=true) ExperimentalHostUserNamespaceDefaulting=true|false (BETA - 默认值=false) GenericEphemeralVolume=true|false (ALPHA - 默认值=false) GracefulNodeShutdown=true|false (ALPHA - 默认值=false) HPAContainerMetrics=true|false (ALPHA - default=false) HPAScaleToZero=true|false (ALPHA - 默认值=false) HugePageStorageMediumSize=true|false (BETA - 默认值=true) IPv6DualStack=true|false (ALPHA - 默认值=false) ImmutableEphemeralVolumes=true|false (BETA - 默认值=true) KubeletCredentialProviders=true|false (ALPHA - 默认值=false) KubeletPodResources=true|false (BETA - 默认值=true) LegacyNodeRoleBehavior=true|false (BETA - 默认值=true) LocalStorageCapacityIsolation=true|false (BETA - 默认值=true) LocalStorageCapacityIsolationFSQuotaMonitoring=true|false (ALPHA - 默认值=false) MixedProtocolLBService=true|false (ALPHA - 默认值=false) NodeDisruptionExclusion=true|false (BETA - 默认值=true) NonPreemptingPriority=true|false (BETA - 默认值=true) PodDisruptionBudget=true|false (BETA - 默认值=true) PodOverhead=true|false (BETA - 默认值=true) ProcMountType=true|false (ALPHA - 默认值=false) QOSReserved=true|false (ALPHA - 默认值=false) RemainingItemCount=true|false (BETA - 默认值=true) RemoveSelfLink=true|false (BETA - 默认值=true) RootCAConfigMap=true|false (BETA - 默认值=true) RotateKubeletServerCertificate=true|false (BETA - 默认值=true) RunAsGroup=true|false (BETA - 默认值=true) ServerSideApply=true|false (BETA - 默认值=true) ServiceAccountIssuerDiscovery=true|false (BETA - 默认值=true) ServiceLBNodePortControl=true|false (ALPHA - 默认值=false) ServiceNodeExclusion=true|false (BETA - 默认值=true) ServiceTopology=true|false (ALPHA - 默认值=false) SetHostnameAsFQDN=true|false (BETA - 默认值=true) SizeMemoryBackedVolumes=true|false (ALPHA - 默认值=false) StorageVersionAPI=true|false (ALPHA - 默认值=false) StorageVersionHash=true|false (BETA - 默认值=true) Sysctls=true|false (BETA - 默认值=true) TTLAfterFinished=true|false (ALPHA - 默认值=false) TopologyManager=true|false (BETA - 默认值=true) ValidateProxyRedirects=true|false (BETA - 默认值=true) WarningHeaders=true|false (BETA - 默认值=true) WinDSR=true|false (ALPHA - 默认值=false) WinOverlay=true|false (BETA - 默认值=true) WindowsEndpointSliceProxying=true|false (ALPHA - 默认值=false) --goaway-chance float 为防止 HTTP/2 客户端卡在单个 apiserver 上,可启用随机关闭连接(GOAWAY)。
客户端的其他运行中请求将不会受到影响,并且客户端将重新连接,
可能会在再次通过负载平衡器后登陆到其他 apiserver 上。
此参数设置将发送 GOAWAY 的请求的比例。
具有单个 apiserver 或不使用负载平衡器的群集不应启用此功能。
最小值为0(关闭),最大值为 .02(1/50 请求); 建议使用 .001(1/1000)。 -h, --help kube-apiserver 的帮助命令 --http2-max-streams-per-connection int 服务器为客户端提供的 HTTP/2 连接中最大流数的限制。
零表示使用 golang 的默认值。 --identity-lease-duration-seconds int 默认值:3600 kube-apiserver 租约时长(按秒计),必须是正数。
(当 APIServerIdentity 特性门控被启用时使用此标志值) --identity-lease-renew-interval-seconds int 默认值:10 kube-apiserver 对其租约进行续期的时间间隔(按秒计),必须是正数。
(当 APIServerIdentity 特性门控被启用时使用此标志值) --kubelet-certificate-authority string 证书颁发机构的证书文件的路径。 --kubelet-client-certificate string TLS 的客户端证书文件的路径。 --kubelet-client-key string TLS 客户端密钥文件的路径。 --kubelet-preferred-address-types stringSlice 默认值:[Hostname,InternalDNS,InternalIP,ExternalDNS,ExternalIP] 用于 kubelet 连接的首选 NodeAddressTypes 列表。 --kubelet-timeout duration 默认值:5s kubelet 操作超时时间。 --kubernetes-service-node-port int 如果非零,那么 Kubernetes 主服务(由 apiserver 创建/维护)将是 NodePort 类型,使用它作为端口的值。
如果为零,则 Kubernetes 主服务将为 ClusterIP 类型。 --livez-grace-period duration 此选项代表 apiserver 完成启动序列并生效所需的最长时间。
从 apiserver 的启动时间到这段时间为止,
/livez 将假定未完成的启动后钩子将成功完成,因此返回 true。 当日志机制执行到'文件 :N'时,生成堆栈跟踪 --log-dir string 如果为非空,则在此目录中写入日志文件 --log-file string 如果为非空,使用此日志文件 --log-file-max-size uint 默认值:1800 定义日志文件可以增长到的最大大小。单位为兆字节。
如果值为 0,则最大文件大小为无限制。 --log-flush-frequency duration 默认值:5s 两次日志刷新之间的最大秒数 --logging-format string 默认值:"text" 设置日志格式。允许的格式:"json","json"。 非默认格式不支持以下标志:--add_dir_header、--alsologtostderr、--log_backtrace_at、--log_dir、--log_file、--log_file_max_size、--logtostderr、--one_output、-skip_headers、-skip_log_headers、--stderrthreshold、-vmodule 和 --log-flush-frequency。 当前非默认选择为 alpha,会随时更改而不会发出警告。 c
--logtostderr 默认值:true 在标准错误而不是文件中输出日志记录 --master-service-namespace string 默认值:"default" 已废弃:应该从其中将 Kubernetes 主服务注入到 Pod 中的名字空间。 --max-connection-bytes-per-sec int 如果不为零,则将每个用户连接限制为该数(字节数/秒)。
当前仅适用于长时间运行的请求。 --max-mutating-requests-inflight int 默认值:200 在给定时间内进行中变更类型请求的最大个数。
当超过该值时,服务将拒绝所有请求。
零表示无限制。 --max-requests-inflight int 默认值:400 在给定时间内进行中非变更类型请求的最大数量。
当超过该值时,服务将拒绝所有请求。
零表示无限制。 --min-request-timeout int 默认值:1800 可选字段,表示处理程序在请求超时前,必须保持其处于打开状态的最小秒数。
当前只对监听(Watch)请求的处理程序有效,它基于这个值选择一个随机数作为连接超时值,以达到分散负载的目的。 --oidc-ca-file string 如果设置该值,将会使用 oidc-ca-file 中的机构之一对 OpenID 服务的证书进行验证,
否则将会使用主机的根 CA 对其进行验证。 --oidc-client-id string OpenID 连接客户端的要使用的客户 ID,如果设置了 oidc-issuer-url,则必须设置这个值。 --oidc-groups-claim string 如果提供该值,这个自定义 OpenID 连接声明将被用来设定用户组。
该声明值需要是一个字符串或字符串数组。
此标志为实验性的,请查阅身份认证相关文档进一步了解详细信息。 --oidc-groups-prefix string 如果提供,则所有组都将以该值作为前缀,以防止与其他身份认证策略冲突。 --oidc-issuer-url string OpenID 颁发者 URL,只接受 HTTPS 方案。
如果设置该值,它将被用于验证 OIDC JSON Web Token(JWT)。 --oidc-required-claim mapStringString 描述 ID 令牌中必需声明的键值对。
如果设置此值,则会验证 ID 令牌中存在与该声明匹配的值。
重复此标志以指定多个声明。 --oidc-signing-algs stringSlice 默认值:[RS256] 允许的 JOSE 非对称签名算法的逗号分隔列表。
若 JWT 所带的 "alg" 标头值不在列表中,则该 JWT 将被拒绝。
取值依据 RFC 7518 https://tools.ietf.org/html/rfc7518#section-3.1 定义。 --oidc-username-claim string 默认值:"sub" 要用作用户名的 OpenID 声明。
请注意,除默认声明("sub")以外的其他声明不能保证是唯一且不可变的。
此标志是实验性的,请参阅身份认证文档以获取更多详细信息。 --oidc-username-prefix string 如果提供,则所有用户名都将以该值作为前缀。
如果未提供,则除 "email" 之外的用户名声明都会添加颁发者 URL 作为前缀,以避免冲突。
要略过添加前缀处理,请设置值为 "-"。 --one-output 此标志为真时,日志只会被写入到其原生的严重性级别中(而不是同时写到所有较低
严重性级别中)。 --permit-port-sharing 如果为 true,则在绑定端口时将使用 SO_REUSEPORT,
这样多个实例可以绑定到同一地址和端口上。[默认值 = false] --profiling 默认值:true 通过 Web 界面启用性能分析 host:port/debug/pprof/ --proxy-client-cert-file string 当必须调用外部程序以处理请求时,用于证明聚合器或者 kube-apiserver 的身份的客户端证书。
包括代理转发到用户 api-server 的请求和调用 Webhook 准入控制插件的请求。
Kubernetes 期望此证书包含来自于 --requestheader-client-ca-file 标志中所给 CA 的签名。
该 CA 在 kube-system 命名空间的 "extension-apiserver-authentication" ConfigMap 中公开。
从 kube-aggregator 收到调用的组件应该使用该 CA 进行各自的双向 TLS 验证。 --proxy-client-key-file string 当必须调用外部程序来处理请求时,用来证明聚合器或者 kube-apiserver 的身份的客户端私钥。
这包括代理转发给用户 api-server 的请求和调用 Webhook 准入控制插件的请求。 --request-timeout duration 默认值:1m0s 可选字段,指示处理程序在超时之前必须保持打开请求的持续时间。
这是请求的默认请求超时,但对于特定类型的请求,可能会被
--min-request-timeout等标志覆盖。 --requestheader-allowed-names stringSlice 此值为客户端证书通用名称(Common Name)的列表;表中所列的表项可以用来提供用户名,
方式是使用 --requestheader-username-headers 所指定的头部。
如果为空,能够通过 --requestheader-client-ca-file 中机构认证的客户端证书都是被允许的。 --requestheader-client-ca-file string 在信任请求头中以 --requestheader-username-headers 指示的用户名之前,
用于验证接入请求中客户端证书的根证书包。
警告:一般不要假定传入请求已被授权。 --requestheader-extra-headers-prefix stringSlice 用于查验请求头部的前缀列表。建议使用 X-Remote-Extra-。 --requestheader-group-headers stringSlice 用于查验用户组的请求头部列表。建议使用 X-Remote-Group。 --requestheader-username-headers stringSlice 用于查验用户名的请求头头列表。建议使用 X-Remote-User。 --runtime-config mapStringString 一组启用或禁用内置 API 的键值对。支持的选项包括: v1=true|false(针对核心 API 组) <group>/<version>=true|false(针对特定 API 组和版本,例如:apps/v1=true) api/all=true|false 控制所有 API 版本 api/ga=true|false 控制所有 v[0-9]+ API 版本 api/beta=true|false 控制所有 v[0-9]+beta[0-9]+ API 版本 api/alpha=true|false 控制所有 v[0-9]+alpha[0-9]+ API 版本 api/legacy 已弃用,并将在以后的版本中删除 --secure-port int 默认值:6443 带身份验证和鉴权机制的 HTTPS 服务端口。
不能用 0 关闭。 --service-account-extend-token-expiration 默认值:true 在生成令牌时,启用投射服务帐户到期时间扩展,
这有助于从旧版令牌安全地过渡到绑定的服务帐户令牌功能。
如果启用此标志,则准入插件注入的令牌的过期时间将延长至 1 年,以防止过渡期间发生意外故障,
并忽略 service-account-max-token-expiration 的值。 --service-account-issuer string 服务帐号令牌颁发者的标识符。
颁发者将在已办法令牌的 "iss" 声明中检查此标识符。
此值为字符串或 URI。
如果根据 OpenID Discovery 1.0 规范检查此选项不是有效的 URI,则即使特性门控设置为 true,
ServiceAccountIssuerDiscovery 功能也将保持禁用状态。
强烈建议该值符合 OpenID 规范:https://openid.net/specs/openid-connect-discovery-1_0.html。
实践中,这意味着 service-account-issuer 取值必须是 HTTPS URL。
还强烈建议此 URL 能够在 {service-account-issuer}/.well-known/openid-configuration
处提供 OpenID 发现文档。 --service-account-jwks-uri string 覆盖 /.well-known/openid-configuration 提供的发现文档中 JSON Web 密钥集的 URI。
如果发现文档和密钥集是通过 API 服务器外部
(而非自动检测到或被外部主机名覆盖)之外的 URL 提供给依赖方的,则此标志很有用。
仅在启用 ServiceAccountIssuerDiscovery 特性门控的情况下有效。 --service-account-key-file stringArray 包含 PEM 编码的 x509 RSA 或 ECDSA 私钥或公钥的文件,用于验证 ServiceAccount 令牌。
指定的文件可以包含多个键,并且可以使用不同的文件多次指定标志。
如果未指定,则使用 --tls-private-key-file。
提供 --service-account-signing-key 时必须指定。 --service-account-lookup 默认值:true 如果为 true,则在身份认证时验证 etcd 中是否存在 ServiceAccount 令牌。 --service-account-max-token-expiration duration 服务帐户令牌发布者创建的令牌的最长有效期。
如果请求有效期大于此值的有效令牌请求,将使用此值的有效期颁发令牌。 --service-account-signing-key-file string 包含服务帐户令牌颁发者当前私钥的文件的路径。
颁发者将使用此私钥签署所颁发的 ID 令牌。 --service-cluster-ip-range string CIDR 表示的 IP 范围用来为服务分配集群 IP。
此地址不得与指定给节点或 Pod 的任何 IP 范围重叠。 --service-node-port-range portRange 默认值:30000-32767 保留给具有 NodePort 可见性的服务的端口范围。
例如:"30000-32767"。范围的两端都包括在内。 --show-hidden-metrics-for-version string 你要显示隐藏指标的先前版本。仅先前的次要版本有意义,不允许其他值。
格式为 <major>.<minor>,例如:"1.16"。
这种格式的目的是确保您有机会注意到下一个版本是否隐藏了其他指标,
而不是在此之后将它们从发行版中永久删除时感到惊讶。 --shutdown-delay-duration duration 延迟终止时间。在此期间,服务器将继续正常处理请求。
端点 /healthz 和 /livez 将返回成功,但是 /readyz 立即返回失败。
在此延迟过去之后,将开始正常终止。
这可用于允许负载平衡器停止向该服务器发送流量。 --skip-headers 如果为 true,日志消息中避免标题前缀 --skip-log-headers 如果为 true,则在打开日志文件时避免标题 --stderrthreshold severity 默认值:2 将达到或超过此阈值的日志写到标准错误输出 --storage-backend string 持久化存储后端。选项:"etcd3"(默认)。 --storage-media-type string 默认值:"application/vnd.kubernetes.protobuf" 用于在存储中存储对象的媒体类型。
某些资源或存储后端可能仅支持特定的媒体类型,并且将忽略此设置。 --tls-cert-file string 包含用于 HTTPS 的默认 x509 证书的文件。(CA 证书(如果有)在服务器证书之后并置)。
如果启用了 HTTPS 服务,并且未提供 --tls-cert-file 和 --tls-private-key-file,
为公共地址生成一个自签名证书和密钥,并将其保存到 --cert-dir 指定的目录中。 --tls-cipher-suites stringSlice 服务器的密码套件的列表,以逗号分隔。如果省略,将使用默认的 Go 密码套件。 首选值:TLS_AES_128_GCM_SHA256、TLS_AES_256_GCM_SHA384、TLS_CHACHA20_POLY1305_SHA256、TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA、TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256、TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA、TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384、TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305、TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256、TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA、TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA、TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256、TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA、TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384、TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305、TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256、TLS_RSA_WITH_3DES_EDE_CBC_SHA、TLS_RSA_WITH_AES_128_CBC_SHA、TLS_RSA_WITH_AES_128_GCM_SHA256、TLS_RSA_WTLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256、TLS_ECDHE_ECDSA_WITH_RC4_128_SHA、TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256、TLS_ECDHE_RSA_WITH_RC4_128_SHA、TLS_RSA_WITH_AES_128_CBC_SHA256、TLS_RSA_WITH_RC4_128_SHA。 --tls-min-version string 支持的最低 TLS 版本。可能的值:VersionTLS10,VersionTLS11,VersionTLS12,VersionTLS13 --tls-private-key-file string 包含匹配 --tls-cert-file 的 x509 证书私钥的文件。 --tls-sni-cert-key namedCertKey 默认值:[] 一对 x509 证书和私钥文件路径,(可选)后缀为全限定域名的域名模式列表,可以使用带有通配符的前缀。
域模式也允许使用 IP 地址,但仅当 apiserver 对客户端请求的IP地址具有可见性时,才应使用 IP。
如果未提供域模式,则提取证书的名称。
非通配符匹配优先于通配符匹配,显式域模式优先于提取出的名称。
对于多个密钥/证书对,请多次使用 --tls-sni-cert-key。
示例:"example.crt,example.key" 或 "foo.crt,foo.key:*.foo.com,foo.com"。 --token-auth-file string 如果设置该值,这个文件将被用于通过令牌认证来保护 API 服务的安全端口。 -v, --v Level 日志级别详细程度的数字 --version version[=true] 打印版本信息并退出 --vmodule moduleSpec 以逗号分隔的 pattern=N 设置列表,用于文件过滤的日志记录 --watch-cache 默认值:true 在 apiserver 中启用监视缓存 --watch-cache-sizes stringSlice 某些资源(pods、nodes 等)的监视缓存大小设置,以逗号分隔。
每个资源对应的设置格式:resource[.group]#size,其中 resource 为小写复数(无版本),
对于 apiVersion v1(旧版核心 API)的资源要省略 group,
对其它资源要给出 group,size 为一个数字。
启用 watch-cache 时,此功能生效。
某些资源(replicationcontrollers、endpoints、nodes、pods、services、apiservices.apiregistration.k8s.io)
具有通过启发式设置的系统默认值,其他资源默认为 default-watch-cache-size
6.9.4 - kube-controller-manager 简介 Kubernetes 控制器管理器是一个守护进程,内嵌随 Kubernetes 一起发布的核心控制回路。
在机器人和自动化的应用中,控制回路是一个永不休止的循环,用于调节系统状态。
在 Kubernetes 中,每个控制器是一个控制回路,通过 API 服务器监视集群的共享状态,
并尝试进行更改以将当前状态转为期望状态。
目前,Kubernetes 自带的控制器例子包括副本控制器、节点控制器、命名空间控制器和服务账号控制器等。
kube-controller-manager [flags]
选项 --add-dir-header 若为 true,将文件目录添加到头部。 --allocate-node-cidrs 基于云驱动来为 Pod 分配和设置子网掩码。 --alsologtostderr 在向文件输出日志的同时,也将日志写到标准输出。 --attach-detach-reconcile-sync-period duration 默认值:1m0s 协调器(reconciler)在相邻两次对存储卷进行挂载和解除挂载操作之间的等待时间。
此时长必须长于 1 秒钟。此值设置为大于默认值时,可能导致存储卷无法与 Pods 匹配。 --authentication-kubeconfig string 此标志值为一个 kubeconfig 文件的路径名。该文件中包含与某 Kubernetes “核心”
服务器相关的信息,并支持足够的权限以创建 tokenreviews.authentication.k8s.io。
此选项是可选的。如果设置为空值,所有令牌请求都会被认作匿名请求,
Kubernetes 也不再在集群中查找客户端的 CA 证书信息。 --authentication-skip-lookup 此值为 false 时,通过 authentication-kubeconfig 参数所指定的文件会被用来
检索集群中缺失的身份认证配置信息。 --authentication-token-webhook-cache-ttl duration 默认值:10s 对 Webhook 令牌认证设施返回结果的缓存时长。 --authentication-tolerate-lookup-failure 此值为 true 时,即使无法从集群中检索到缺失的身份认证配置信息也无大碍。
需要注意的是,这样设置可能导致所有请求都被视作匿名请求。 --authorization-always-allow-paths stringSlice 默认值:[/healthz] 鉴权过程中会忽略的一个 HTTP 路径列表。
换言之,控制器管理器会对列表中路径的访问进行授权,并且无须征得
Kubernetes “核心” 服务器同意。 --authorization-kubeconfig string 包含 Kubernetes “核心” 服务器信息的 kubeconfig 文件路径,
所包含信息具有创建 subjectaccessreviews.authorization.k8s.io 的足够权限。
此参数是可选的。如果配置为空字符串,未被鉴权模块所忽略的请求都会被禁止。 --authorization-webhook-cache-authorized-ttl duration 默认值:10s 对 Webhook 形式鉴权组件所返回的“已授权(Authorized)”响应的缓存时长。 --authorization-webhook-cache-unauthorized-ttl duration 默认值:10s 对 Webhook 形式鉴权组件所返回的“未授权(Unauthorized)”响应的缓存时长。 --azure-container-registry-config string 指向包含 Azure 容器仓库配置信息的文件的路径名。 --bind-address ip 默认值:0.0.0.0 针对 --secure-port 端口上请求执行监听操作的 IP 地址。
所对应的网络接口必须从集群中其它位置可访问(含命令行及 Web 客户端)。
如果此值为空或者设定为非特定地址(0.0.0.0 或 ::),意味着所有网络接口都在监听范围。 --cert-dir string TLS 证书所在的目录。如果提供了 --tls-cert-file 和 --tls-private-key-file,此标志会被忽略。 --cidr-allocator-type string 默认值:"RangeAllocator" 要使用的 CIDR 分配器类型。 --client-ca-file string 如果设置了此标志,对于所有能够提供客户端证书的请求,若该证书由
client-ca-file 中所给机构之一签署,则该请求会被成功认证为客户端证书中
CommonName 所给的实体。 --cloud-config string 云驱动程序配置文件的路径。空字符串表示没有配置文件。 --cloud-provider string 云服务的提供者。空字符串表示没有对应的提供者(驱动)。 --cluster-cidr string 集群中 Pods 的 CIDR 范围。要求 --allocate-node-cidrs 标志为 true。 --cluster-name string 默认值:"kubernetes" 集群实例的前缀。 --cluster-signing-cert-file string 默认值:"/etc/kubernetes/ca/ca.pem" 包含 PEM 编码格式的 X509 CA 证书的文件名。该证书用来发放集群范围的证书。
如果设置了此标志,则不需要锦衣设置 --cluster-signing-* 标志。 --cluster-signing-duration duration 默认值:8760h0m0s 所签名证书的有效期限。 --cluster-signing-key-file string 默认值:"/etc/kubernetes/ca/ca.key" 包含 PEM 编码的 RSA 或 ECDSA 私钥的文件名。该私钥用来对集群范围证书签名。 --cluster-signing-kube-apiserver-client-cert-file string 包含 PEM 编码的 X509 CA 证书的文件名,
该证书用于为 kubernetes.io/kube-apiserver-client 签署者颁发证书。
如果指定,则不得设置 --cluster-signing-{cert,key}-file。 --cluster-signing-kube-apiserver-client-key-file string 包含 PEM 编码的 RSA 或 ECDSA 私钥的文件名,
该私钥用于为 kubernetes.io/kube-apiserver-client 签署者签名证书。
如果指定,则不得设置 --cluster-signing-{cert,key}-file。 --cluster-signing-kubelet-client-cert-file string 包含 PEM 编码的 X509 CA 证书的文件名,
该证书用于为 kubernetes.io/kube-apiserver-client-kubelet 签署者颁发证书。
如果指定,则不得设置 --cluster-signing-{cert,key}-file。 --cluster-signing-kubelet-client-key-file string 包含 PEM 编码的 RSA 或 ECDSA 私钥的文件名,
该私钥用于为 kubernetes.io/kube-apiserver-client-kubelet 签署者签名证书。
如果指定,则不得设置 --cluster-signing-{cert,key}-file。 --cluster-signing-kubelet-serving-cert-file string 包含 PEM 编码的 X509 CA 证书的文件名,
该证书用于为 kubernetes.io/kubelet-serving 签署者颁发证书。
如果指定,则不得设置 --cluster-signing-{cert,key}-file。 --cluster-signing-kubelet-serving-key-file string 包含 PEM 编码的 RSA或ECDSA 私钥的文件名,
该私钥用于对 kubernetes.io/kubelet-serving 签署者的证书进行签名。
如果指定,则不得设置 --cluster-signing-{cert,key}-file。 --cluster-signing-legacy-unknown-cert-file string 包含 PEM 编码的 X509 CA 证书的文件名,
用于为 kubernetes.io/legacy-unknown 签署者颁发证书。
如果指定,则不得设置 --cluster-signing-{cert,key}-file。 --cluster-signing-legacy-unknown-key-file string 包含 PEM 编码的 RSA 或 ECDSA 私钥的文件名,
用于为 kubernetes.io/legacy-unknown 签署者签名证书。
如果指定,则不得设置 --cluster-signing-{cert,key}-file。 --concurrent-deployment-syncs int32 默认值:5 可以并发同步的 Deployment 对象个数。数值越大意味着对 Deployment 的响应越及时,
同时也意味着更大的 CPU(和网络带宽)压力。 --concurrent-endpoint-syncs int32 默认值:5 可以并发执行的 Endpoints 同步操作个数。数值越大意味着更快的 Endpoints 更新操作,
同时也意味着更大的 CPU (和网络)压力。 --concurrent-gc-syncs int32 默认值:20 可以并发同步的垃圾收集工作线程个数。 --concurrent-namespace-syncs int32 默认值:10 可以并发同步的 Namespace 对象个数。较大的数值意味着更快的名字空间终结操作,
不过也意味着更多的 CPU (和网络)占用。 --concurrent-replicaset-syncs int32 默认值:5 可以并发同步的 ReplicaSet 个数。数值越大意味着副本管理的响应速度越快,
同时也意味着更多的 CPU (和网络)占用。 --concurrent-resource-quota-syncs int32 默认值:5 可以并发同步的 ResourceQuota 对象个数。数值越大,配额管理的响应速度越快,
不过对 CPU (和网络)的占用也越高。 --concurrent-service-endpoint-syncs int32 默认值:5 可以并发执行的服务端点同步操作个数。数值越大,端点片段(Endpoint Slice)
的更新速度越快,不过对 CPU (和网络)的占用也越高。默认值为 5。 --concurrent-service-syncs int32 默认值:1 可以并发同步的 Service 对象个数。数值越大,服务管理的响应速度越快,
不过对 CPU (和网络)的占用也越高。 --concurrent-serviceaccount-token-syncs int32 默认值:5 可以并发同步的服务账号令牌对象个数。数值越大,令牌生成的速度越快,
不过对 CPU (和网络)的占用也越高。 --concurrent-statefulset-syncs int32 默认值:5 可以并发同步的 StatefulSet 对象个数。数值越大,StatefulSet 管理的响应速度越快,
不过对 CPU (和网络)的占用也越高。 --concurrent-ttl-after-finished-syncs int32 默认值:5 可以并发同步的 TTL-after-finished 控制器线程个数。 --concurrent_rc_syncs int32 默认值:5 可以并发同步的 ReplicationController 对象个数。数值越大,副本管理的响应速度越快,
不过对 CPU (和网络)的占用也越高。 --configure-cloud-routes 默认值:true 决定是否由 --allocate-node-cidrs 所分配的 CIDR 要通过云驱动程序来配置。 --contention-profiling 在启用了性能分析(profiling)时,也启用锁竞争情况分析。 --controller-start-interval duration 在两次启动控制器管理器之间的时间间隔。 --controllers stringSlice 默认值:[*] 要启用的控制器列表。* 表示启用所有默认启用的控制器;foo 启用名为 foo 的控制器;
-foo 表示禁用名为 foo 的控制器。 控制器的全集:attachdetach、bootstrapsigner、cloud-node-lifecycle、clusterrole-aggregation、cronjob、csrapproving、csrcleaner、csrsigning、daemonset、deployment、disruption、endpoint、endpointslice、endpointslicemirroring、ephemeral-volume、garbagecollector、horizontalpodautoscaling、job、namespace、nodeipam、nodelifecycle、persistentvolume-binder、persistentvolume-expander、podgc、pv-protection、pvc-protection、replicaset、replicationcontroller、resourcequota、root-ca-cert-publisher、route、service、serviceaccount、serviceaccount-token、statefulset、tokencleaner、ttl、ttl-after-finished 默认禁用的控制器有:bootstrapsigner 和 tokencleaner。 --deployment-controller-sync-period duration 默认值:30s Deployment 资源的同步周期。 --disable-attach-detach-reconcile-sync 禁用卷挂接/解挂调节器的同步。禁用此同步可能导致卷存储与 Pod 之间出现错位。请小心使用。 --enable-dynamic-provisioning 默认值:true 在环境允许的情况下启用动态卷制备。 --enable-garbage-collector 默认值:true 启用通用垃圾收集器。必须与 kube-apiserver 中对应的标志一致。 --enable-hostpath-provisioner 在没有云驱动程序的情况下,启用 HostPath 持久卷的制备。
此参数便于对卷供应功能进行开发和测试。HostPath 卷的制备并非受支持的功能特性,
在多节点的集群中也无法工作,因此除了开发和测试环境中不应使用。 --enable-taint-manager 默认值:true 警告:此为Beta 阶段特性。设置为 true 时会启用 NoExecute 污点,
并在所有标记了此污点的节点上逐出所有无法忍受该污点的 Pods。 --endpoint-updates-batch-period duration 端点(Endpoint)批量更新周期时长。对 Pods 变更的处理会被延迟,
以便将其与即将到来的更新操作合并,从而减少端点更新操作次数。
较大的数值意味着端点更新的迟滞时间会增长,也意味着所生成的端点版本个数会变少。 --endpointslice-updates-batch-period duration 端点片段(Endpoint Slice)批量更新周期时长。对 Pods 变更的处理会被延迟,
以便将其与即将到来的更新操作合并,从而减少端点更新操作次数。
较大的数值意味着端点更新的迟滞时间会增长,也意味着所生成的端点版本个数会变少。 --experimental-logging-sanitization [试验性功能] 当启用此标志时,被标记为敏感的字段(密码、密钥、令牌)不会被日志输出。 运行时的日志清理操作可能会引入相当程度的计算开销,因此不应在生产环境中启用。 --external-cloud-volume-plugin string 当云驱动程序设置为 external 时要使用的插件名称。此字符串可以为空。
只能在云驱动程序为 external 时设置。目前用来保证节点控制器和卷控制器能够
在三种云驱动上正常工作。 --feature-gates mapStringBool 一组 key=value 对,用来描述测试性/试验性功能的特性门控(Feature Gate)。可选项有: APIListChunking=true|false (BETA - 默认值=true) APIPriorityAndFairness=true|false (BETA - 默认值=true) APIResponseCompression=true|false (BETA - 默认值=true) APIServerIdentity=true|false (ALPHA - 默认值=false) AllAlpha=true|false (ALPHA - 默认值=false) AllBeta=true|false (BETA - 默认值=false) AllowInsecureBackendProxy=true|false (BETA - 默认值=true) AnyVolumeDataSource=true|false (ALPHA - 默认值=false) AppArmor=true|false (BETA - 默认值=true) BalanceAttachedNodeVolumes=true|false (ALPHA - 默认值=false) BoundServiceAccountTokenVolume=true|false (ALPHA - 默认值=false) CPUManager=true|false (BETA - 默认值=true) CRIContainerLogRotation=true|false (BETA - 默认值=true) CSIInlineVolume=true|false (BETA - 默认值=true) CSIMigration=true|false (BETA - 默认值=true) CSIMigrationAWS=true|false (BETA - 默认值=false) CSIMigrationAWSComplete=true|false (ALPHA - 默认值=false) CSIMigrationAzureDisk=true|false (BETA - 默认值=false) CSIMigrationAzureDiskComplete=true|false (ALPHA - 默认值=false) CSIMigrationAzureFile=true|false (ALPHA - 默认值=false) CSIMigrationAzureFileComplete=true|false (ALPHA - 默认值=false) CSIMigrationGCE=true|false (BETA - 默认值=false) CSIMigrationGCEComplete=true|false (ALPHA - 默认值=false) CSIMigrationOpenStack=true|false (BETA - 默认值=false) CSIMigrationOpenStackComplete=true|false (ALPHA - 默认值=false) CSIMigrationvSphere=true|false (BETA - 默认值=false) CSIMigrationvSphereComplete=true|false (BETA - 默认值=false) CSIServiceAccountToken=true|false (ALPHA - 默认值=false) CSIStorageCapacity=true|false (ALPHA - 默认值=false) CSIVolumeFSGroupPolicy=true|false (BETA - 默认值=true) ConfigurableFSGroupPolicy=true|false (BETA - 默认值=true) CronJobControllerV2=true|false (ALPHA - 默认值=false) CustomCPUCFSQuotaPeriod=true|false (ALPHA - 默认值=false) DefaultPodTopologySpread=true|false (BETA - 默认值=true) DevicePlugins=true|false (BETA - 默认值=true) DisableAcceleratorUsageMetrics=true|false (BETA - 默认值=true) DownwardAPIHugePages=true|false (ALPHA - 默认值=false) DynamicKubeletConfig=true|false (BETA - 默认值=true) EfficientWatchResumption=true|false (ALPHA - 默认值=false) EndpointSlice=true|false (BETA - 默认值=true) EndpointSliceNodeName=true|false (ALPHA - 默认值=false) EndpointSliceProxying=true|false (BETA - 默认值=true) EndpointSliceTerminatingCondition=true|false (ALPHA - 默认值=false) EphemeralContainers=true|false (ALPHA - 默认值=false) ExpandCSIVolumes=true|false (BETA - 默认值=true) ExpandInUsePersistentVolumes=true|false (BETA - 默认值=true) ExpandPersistentVolumes=true|false (BETA - 默认值=true) ExperimentalHostUserNamespaceDefaulting=true|false (BETA - 默认值=false) GenericEphemeralVolume=true|false (ALPHA - 默认值=false) GracefulNodeShutdown=true|false (ALPHA - 默认值=false) HPAContainerMetrics=true|false (ALPHA - 默认值=false) HPAScaleToZero=true|false (ALPHA - 默认值=false) HugePageStorageMediumSize=true|false (BETA - 默认值=true) IPv6DualStack=true|false (ALPHA - 默认值=false) ImmutableEphemeralVolumes=true|false (BETA - 默认值=true) KubeletCredentialProviders=true|false (ALPHA - 默认值=false) KubeletPodResources=true|false (BETA - 默认值=true) LegacyNodeRoleBehavior=true|false (BETA - 默认值=true) LocalStorageCapacityIsolation=true|false (BETA - 默认值=true) LocalStorageCapacityIsolationFSQuotaMonitoring=true|false (ALPHA - 默认值=false) MixedProtocolLBService=true|false (ALPHA - 默认值=false) NodeDisruptionExclusion=true|false (BETA - 默认值=true) NonPreemptingPriority=true|false (BETA - 默认值=true) PodDisruptionBudget=true|false (BETA - 默认值=true) PodOverhead=true|false (BETA - 默认值=true) ProcMountType=true|false (ALPHA - 默认值=false) QOSReserved=true|false (ALPHA - 默认值=false) RemainingItemCount=true|false (BETA - 默认值=true) RemoveSelfLink=true|false (BETA - 默认值=true) RootCAConfigMap=true|false (BETA - 默认值=true) RotateKubeletServerCertificate=true|false (BETA - 默认值=true) RunAsGroup=true|false (BETA - 默认值=true) ServerSideApply=true|false (BETA - 默认值=true) ServiceAccountIssuerDiscovery=true|false (BETA - 默认值=true) ServiceLBNodePortControl=true|false (ALPHA - 默认值=false) ServiceNodeExclusion=true|false (BETA - 默认值=true) ServiceTopology=true|false (ALPHA - 默认值=false) SetHostnameAsFQDN=true|false (BETA - 默认值=true) SizeMemoryBackedVolumes=true|false (ALPHA - 默认值=false) StorageVersionAPI=true|false (ALPHA - 默认值=false) StorageVersionHash=true|false (BETA - 默认值=true) Sysctls=true|false (BETA - 默认值=true) TTLAfterFinished=true|false (ALPHA - 默认值=false) TopologyManager=true|false (BETA - 默认值=true) ValidateProxyRedirects=true|false (BETA - 默认值=true) WarningHeaders=true|false (BETA - 默认值=true) WinDSR=true|false (ALPHA - 默认值=false) WinOverlay=true|false (BETA - 默认值=true) WindowsEndpointSliceProxying=true|false (ALPHA - 默认值=false) --flex-volume-plugin-dir string 默认值:"/usr/libexec/kubernetes/kubelet-plugins/volume/exec/" FlexVolume 插件要搜索第三方卷插件的目录路径。 -h, --help kube-controller-manager 的帮助信息。 --horizontal-pod-autoscaler-cpu-initialization-period duration 默认值:5m0s Pod 启动之后可以忽略 CPU 采样值的时长。 --horizontal-pod-autoscaler-downscale-stabilization duration 默认值:5m0s 自动扩缩程序的回溯时长。自动扩缩器不会基于在给定的时长内所建议的规模对负载执行规模缩小的操作。 --horizontal-pod-autoscaler-initial-readiness-delay duration 默认值:30s Pod 启动之后,在此值所给定的时长内,就绪状态的变化都不会作为初始的就绪状态。 --horizontal-pod-autoscaler-sync-period duration 默认值:15s 水平 Pod 扩缩器对 Pods 数目执行同步操作的周期。 --horizontal-pod-autoscaler-tolerance float 默认值:0.1 此值为目标值与实际值的比值与 1.0 的差值。只有超过此标志所设的阈值时,HPA 才会考虑执行缩放操作。 --http2-max-streams-per-connection int 服务器为客户端所设置的 HTTP/2 连接中流式连接个数上限。
此值为 0 表示采用 Go 语言库所设置的默认值。 --kube-api-burst int32 默认值:30 与 Kubernetes API 服务器通信时突发峰值请求个数上限。 --kube-api-content-type string 默认值:"application/vnd.kubernetes.protobuf" 向 API 服务器发送请求时使用的内容类型(Content-Type)。 --kube-api-qps float32 默认值:20 与 API 服务器通信时每秒请求数(QPS)限制。 --kubeconfig string 指向 kubeconfig 文件的路径。该文件中包含主控节点位置以及鉴权凭据信息。 --large-cluster-size-threshold int32 默认值:50 节点控制器在执行 Pod 逐出操作逻辑时,基于此标志所设置的节点个数阈值来判断
所在集群是否为大规模集群。当集群规模小于等于此规模时,
--secondary-node-eviction-rate 会被隐式重设为 0。 --leader-elect 默认值:true 在执行主循环之前,启动领导选举(Leader Election)客户端,并尝试获得领导者身份。
在运行多副本组件时启用此标志有助于提高可用性。 --leader-elect-lease-duration duration 默认值:15s 对于未获得领导者身份的节点,在探测到领导者身份需要更迭时需要等待
此标志所设置的时长,才能尝试去获得曾经是领导者但尚未续约的席位。
本质上,这个时长也是现有领导者节点在被其他候选节点替代之前可以停止
的最长时长。只有集群启用了领导者选举机制时,此标志才起作用。 --leader-elect-renew-deadline duration 默认值:10s 当前执行领导者角色的节点在被停止履行领导职责之前可多次尝试续约领导者身份;
此标志给出相邻两次尝试之间的间歇时长。
此值必须小于或等于租期时长(Lease Duration)。仅在集群启用了领导者选举时有效。 --leader-elect-resource-lock string 默认值:"endpointsleases" 在领导者选举期间用于锁定的资源对象的类型。 支持的选项为 "endpoints"、
"configmaps"、"leases"、"endpointsleases" 和 "configmapsleases"。 --leader-elect-resource-name string 默认值:"kube-controller-manager" 在领导者选举期间,用来执行锁操作的资源对象名称。 --leader-elect-resource-namespace string 默认值:"kube-system" 在领导者选举期间,用来执行锁操作的资源对象的名字空间。 --leader-elect-retry-period duration 默认值:2s 尝试获得领导者身份时,客户端在相邻两次尝试之间要等待的时长。此标志仅在启用了领导者选举的集群中起作用。 --log-backtrace-at traceLocation 默认值::0 当执行到 file:N 所给的文件和代码行时,日志机制会生成一个调用栈快照。 --log-dir string 此标志为非空字符串时,日志文件会写入到所给的目录中。 --log-file string 此标志为非空字符串时,意味着日志会写入到所给的文件中。 --log-file-max-size uint 默认值:1800 定义日志文件大小的上限。单位是兆字节(MB)。
若此值为 0,则不对日志文件尺寸进行约束。 --log-flush-frequency duration 默认值:5s 将内存中日志数据清除到日志文件中时,相邻两次清除操作之间最大间隔秒数。 --logging-format string 默认值:"text" 设置日志格式。允许的格式:"text","json"。 非默认格式不支持以下标志:--add_dir_header、--alsologtostderr、--log_backtrace_at、--log_dir、--log_file、--log_file_max_size、--logtostderr、--one_output、--skip_headers、--skip_log_headers、--stderrthreshold、--vmodule、--log-flush-frequency。 当前非默认选项为 Alpha,如有更改,恕不另行通知。 --logtostderr 默认值:true 将日志写出到标准错误输出(stderr)而不是写入到日志文件。 --master string Kubernetes API 服务器的地址。此值会覆盖 kubeconfig 文件中所给的地址。 --max-endpoints-per-slice int32 默认值:100 每个 EndpointSlice 中可以添加的端点个数上限。每个片段中端点个数越多,
得到的片段个数越少,但是片段的规模会变得更大。默认值为 100。 --min-resync-period duration 默认值:12h0m0s 自省程序的重新同步时隔下限。实际时隔长度会在 min-resync-period 和
2 * min-resync-period 之间。 --mirroring-concurrent-service-endpoint-syncs int32 默认值:5 EndpointSliceMirroring 控制器将同时执行的服务端点同步操作数。
较大的数量 = 更快的端点切片更新,但 CPU(和网络)负载更多。 默认为 5。 --mirroring-endpointslice-updates-batch-period duration EndpointSlice 的长度更新了 EndpointSliceMirroring 控制器的批处理周期。
EndpointSlice 更改的处理将延迟此持续时间,
以使它们与潜在的即将进行的更新结合在一起,并减少 EndpointSlice 更新的总数。
较大的数量 = 较高的端点编程延迟,但是生成的端点修订版本数量较少 --mirroring-max-endpoints-per-subset int32 默认值:1000 EndpointSliceMirroring 控制器将添加到 EndpointSlice 的最大端点数。
每个分片的端点越多,端点分片越少,但资源越大。
默认为 100。 --namespace-sync-period duration 默认值:5m0s 对名字空间对象进行同步的周期。 --node-cidr-mask-size int32 集群中节点 CIDR 的掩码长度。对 IPv4 而言默认为 24;对 IPv6 而言默认为 64。 --node-cidr-mask-size-ipv4 int32 在双堆栈(同时支持 IPv4 和 IPv6)的集群中,节点 IPV4 CIDR 掩码长度。默认为 24。 --node-cidr-mask-size-ipv6 int32 在双堆栈(同时支持 IPv4 和 IPv6)的集群中,节点 IPv6 CIDR 掩码长度。默认为 64。 --node-eviction-rate float32 默认值:0.1 当某区域变得不健康,节点失效时,每秒钟可以从此标志所设定的节点
个数上删除 Pods。请参阅 --unhealthy-zone-threshold
以了解“健康”的判定标准。这里的区域(zone)在集群并不跨多个区域时
指的是整个集群。 --node-monitor-grace-period duration 默认值:40s 在将一个 Node 标记为不健康之前允许其无响应的时长上限。
必须比 kubelet 的 nodeStatusUpdateFrequency 大 N 倍;
这里 N 指的是 kubelet 发送节点状态的重试次数。 --node-monitor-period duration 默认值:5s 节点控制器对节点状态进行同步的重复周期。 --node-startup-grace-period duration 默认值:1m0s 在节点启动期间,节点可以处于无响应状态;
但超出此标志所设置的时长仍然无响应则该节点被标记为不健康。 --one-output 如果此标志为 true,则仅将日志写入其自身的严重性级别(而不是同时写入更低的严重性级别中)。 --permit-port-sharing 如果为 true,则在绑定端口时将使用 SO_REUSEPORT,
这允许多个实例在同一地址和端口上进行绑定。
[默认值 = false] --pod-eviction-timeout duration 默认值:5m0s 在失效的节点上删除 Pods 时为其预留的宽限期。 --profiling 默认值:true 通过位于 host:port/debug/pprof/ 的 Web 接口启用性能分析。 --pv-recycler-increment-timeout-nfs int32 默认值:30 NFS 清洗 Pod 在清洗用过的卷时,根据此标志所设置的秒数,为每清洗 1 GiB 数据
增加对应超时时长,作为 activeDeadlineSeconds。 --pv-recycler-minimum-timeout-hostpath int32 默认值:60 对于 HostPath 回收器 Pod,设置其 activeDeadlineSeconds 参数下限。
此参数仅用于开发和测试目的,不适合在多节点集群中使用。 --pv-recycler-minimum-timeout-nfs int32 默认值:300 NFS 回收器 Pod 要使用的 activeDeadlineSeconds 参数下限。 --pv-recycler-pod-template-filepath-hostpath string 对 HostPath 持久卷进行回收利用时,用作模版的 Pod 定义文件所在路径。
此标志仅用于开发和测试目的,不适合多节点集群中使用。 --pv-recycler-pod-template-filepath-nfs string 对 NFS 卷执行回收利用时,用作模版的 Pod 定义文件所在路径。 --pv-recycler-timeout-increment-hostpath int32 默认值:30 HostPath 清洗器 Pod 在清洗对应类型持久卷时,为每 GiB 数据增加此标志所设置的秒数,
作为其 activeDeadlineSeconds 参数。此标志仅用于开发和测试环境,不适合多节点集群环境。 --pvclaimbinder-sync-period duration 默认值:15s 持久卷(PV)和持久卷申领(PVC)对象的同步周期。 --requestheader-allowed-names stringSlice 标志值是客户端证书中的 Common Names 列表。其中所列的名称可以通过
--requestheader-username-headers 所设置的 HTTP 头部来提供用户名。
如果此标志值为空表,则被 --requestheader-client-ca-file
中机构所验证过的所有客户端证书都是允许的。 --requestheader-client-ca-file string 根证书包文件名。在信任通过 --requestheader-username-headers
所指定的任何用户名之前,要使用这里的证书来检查请求中的客户证书。
警告:一般不要依赖对请求所作的鉴权结果。 --requestheader-extra-headers-prefix stringSlice 默认值:[x-remote-extra-] 要插入的请求头部前缀。建议使用 X-Remote-Exra-。 --requestheader-group-headers stringSlice 默认值:[x-remote-group] 用来检查用户组名的请求头部名称列表。建议使用 X-Remote-Group。 --requestheader-username-headers stringSlice 默认值:[x-remote-user] 用来检查用户名的请求头部名称列表。建议使用 X-Remote-User。 --resource-quota-sync-period duration 默认值:5m0s 对系统中配额用量信息进行同步的周期。 --root-ca-file string 如果此标志非空,则在服务账号的令牌 Secret 中会包含此根证书机构。
所指定标志值必须是一个合法的 PEM 编码的 CA 证书包。 --route-reconciliation-period duration 默认值:10s 对云驱动为节点所创建的路由信息进行调解的周期。 --secondary-node-eviction-rate float32 默认值:0.01 当区域不健康,节点失效时,每秒钟从此标志所给的节点个数上删除 Pods。
参见 --unhealthy-zone-threshold 以了解“健康与否”的判定标准。
在只有一个区域的集群中,区域指的是整个集群。如果集群规模小于
--large-cluster-size-threshold 所设置的节点个数时,此值被隐式地重设为 0。 --secure-port int 默认值:10257 在此端口上提供 HTTPS 身份认证和鉴权操作。若此标志值为 0,则不提供 HTTPS 服务。 --service-account-private-key-file string 包含 PEM 编码的 RSA 或 ECDSA 私钥数据的文件名,这些私钥用来对服务账号令牌签名。 --service-cluster-ip-range string 集群中 Service 对象的 CIDR 范围。要求 --allocate-node-cidrs 标志为 true。 --show-hidden-metrics-for-version string 你希望展示隐藏度量值的上一个版本。只有上一个次版本号有意义,其他值都是不允许的。
字符串格式为 "<major>.<minor>"。例如:"1.16"。
此格式的目的是确保你能够有机会注意到下一个版本隐藏了一些额外的度量值,
而不是在更新版本中某些度量值被彻底删除时措手不及。 --skip-headers 若此标志为 true,则在日志消息中避免写入头部前缀信息。 --skip-log-headers 若此标志为 true,则在写入日志文件时避免写入头部信息。 --stderrthreshold severity 默认值:2 等于或大于此阈值的日志信息会被写入到标准错误输出(stderr)。 --terminated-pod-gc-threshold int32 默认值:12500 在已终止 Pods 垃圾收集器删除已终止 Pods 之前,可以保留的已删除
Pods 的个数上限。若此值小于等于 0,则相当于禁止垃圾回收已终止的 Pods。 --tls-cert-file string 包含 HTTPS 所用的默认 X509 证书的文件。如果有 CA 证书,会被串接在服务器证书之后。
若启用了 HTTPS 服务且 --tls-cert-file 和 --tls-private-key-file 标志未设置,
则为节点的公开地址生成自签名的证书和密钥,并保存到 --cert-dir 所给的目录中。 --tls-cipher-suites stringSlice 供服务器使用的加密包的逗号分隔列表。若忽略此标志,则使用 Go 语言默认的加密包。 可选值包括:TLS_AES_128_GCM_SHA256、TLS_AES_256_GCM_SHA384、TLS_CHACHA20_POLY1305_SHA256、TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA、TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256、TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA、TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384、TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305、TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256、TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA、TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA、TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256、TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA、TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384、TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305、TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256、TLS_RSA_WITH_3DES_EDE_CBC_SHA、TLS_RSA_WITH_AES_128_CBC_SHA、TLS_RSA_WITH_AES_128_GCM_SHA256、TLS_RSA_WITH_AES_256_CBC_SHA、TLS_RSA_WITH_AES_256_GCM_SHA384. 不安全的值: TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256、TLS_ECDHE_ECDSA_WITH_RC4_128_SHA、TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256、TLS_ECDHE_RSA_WITH_RC4_128_SHA、TLS_RSA_WITH_AES_128_CBC_SHA256、TLS_RSA_WITH_RC4_128_SHA --tls-min-version string 可支持的最低 TLS 版本。可选值包括:
“VersionTLS10”、“VersionTLS11”、“VersionTLS12”、“VersionTLS13”。 --tls-private-key-file string 包含与 --tls-cert-file 对应的默认 X509 私钥的文件。 --tls-sni-cert-key namedCertKey 默认值:[] X509 证书和私钥文件路径的耦对。作为可选项,可以添加域名模式的列表,
其中每个域名模式都是可以带通配片段前缀的全限定域名(FQDN)。
域名模式也可以使用 IP 地址字符串,不过只有 API 服务器在所给 IP 地址上
对客户端可见时才可以使用 IP 地址。在未提供域名模式时,从证书中提取域名。
如果有非通配方式的匹配,则优先于通配方式的匹配;显式的域名模式优先于提取的域名。
当存在多个密钥/证书耦对时,可以多次使用 --tls-sni-cert-key 标志。
例如:example.crt,example.key 或 foo.crt,foo.key:*.foo.com,foo.com。 --unhealthy-zone-threshold float32 默认值:0.55 仅当给定区域中处于非就绪状态的节点(最少 3 个)的占比高于此值时,才将该区域视为不健康。 --use-service-account-credentials 当此标志为 true 时,为每个控制器单独使用服务账号凭据。 -v, --v Level 日志级别详细程度取值 --version version[=true] 打印版本信息之后退出 --vmodule moduleSpec 由逗号分隔的列表,每一项都是 pattern=N 格式,用来执行根据文件过滤的日志行为。 --volume-host-allow-local-loopback 默认值:true 此标志为 false 时,禁止本地回路 IP 地址和 --volume-host-cidr-denylist
中所指定的 CIDR 范围。 --volume-host-cidr-denylist stringSlice 用逗号分隔的一个 CIDR 范围列表,禁止使用这些地址上的卷插件。
6.9.5 - kube-proxy 简介 Kubernetes 网络代理在每个节点上运行。网络代理反映了每个节点上 Kubernetes API 中定义的服务,并且可以执行简单的 TCP、UDP 和 SCTP 流转发,或者在一组后端进行循环 TCP、UDP 和 SCTP 转发。当前可通过 Docker-links-compatible 环境变量找到服务集群 IP 和端口,这些环境变量指定了服务代理打开的端口。有一个可选的插件,可以为这些集群 IP 提供集群 DNS。用户必须使用 apiserver API 创建服务才能配置代理。
kube-proxy [flags]
选项 --azure-container-registry-config string 包含 Azure 容器仓库配置信息的文件的路径。 --bind-address 0.0.0.0 默认值: 0.0.0.0 代理服务器要使用的 IP 地址(对于所有 IPv4 接口设置为 0.0.0.0,对于所有 IPv6 接口设置为 ::) --cleanup 如果为 true,清理 iptables 和 ipvs 规则并退出。 --cleanup-ipvs 默认值: true 如果设置为 true 并指定了 --cleanup,则 kube-proxy 除了常规清理外,还将刷新 IPVS 规则。 --cluster-cidr string 集群中 Pod 的 CIDR 范围。配置后,将从该范围之外发送到服务集群 IP 的流量被伪装,从 Pod 发送到外部 LoadBalancer IP 的流量将被重定向到相应的集群 IP。 --config string 配置文件的路径。 --config-sync-period duration 默认值: 15m0s 来自 apiserver 的配置的刷新频率。必须大于 0。 --conntrack-max-per-core int32 默认值: 32768 每个 CPU 核跟踪的最大 NAT 连接数(0 表示保留原样限制并忽略 conntrack-min)。 --conntrack-min int32 默认值: 131072 无论 conntrack-max-per-core 多少,要分配的 conntrack 条目的最小数量(将 conntrack-max-per-core 设置为 0 即可保持原样的限制)。 --conntrack-tcp-timeout-close-wait duration 默认值: 1h0m0s 处于 CLOSE_WAIT 状态的 TCP 连接的 NAT 超时 --conntrack-tcp-timeout-established duration 默认值: 24h0m0s 已建立的 TCP 连接的空闲超时(0 保持原样) --detect-local-mode LocalMode 用于检测本地流量的模式 --feature-gates mapStringBool 一组键=值(key=value)对,描述了 alpha/experimental 的特征。可选项有: APIListChunking=true|false (BETA - 默认值=true) APIPriorityAndFairness=true|false (ALPHA - 默认值=false) APIResponseCompression=true|false (BETA - 默认值=true) AllAlpha=true|false (ALPHA - 默认值=false) AllBeta=true|false (BETA - 默认值=false) AllowInsecureBackendProxy=true|false (BETA - 默认值=true) AnyVolumeDataSource=true|false (ALPHA - 默认值=false) AppArmor=true|false (BETA - 默认值=true) BalanceAttachedNodeVolumes=true|false (ALPHA - 默认值=false) BoundServiceAccountTokenVolume=true|false (ALPHA - 默认值=false) CPUManager=true|false (BETA - 默认值=true) CRIContainerLogRotation=true|false (BETA - 默认值=true) CSIInlineVolume=true|false (BETA - 默认值=true) CSIMigration=true|false (BETA - 默认值=true) CSIMigrationAWS=true|false (BETA - 默认值=false) CSIMigrationAWSComplete=true|false (ALPHA - 默认值=false) CSIMigrationAzureDisk=true|false (BETA - 默认值=false) CSIMigrationAzureDiskComplete=true|false (ALPHA - 默认值=false) CSIMigrationAzureFile=true|false (ALPHA - 默认值=false) CSIMigrationAzureFileComplete=true|false (ALPHA - 默认值=false) CSIMigrationGCE=true|false (BETA - 默认值=false) CSIMigrationGCEComplete=true|false (ALPHA - 默认值=false) CSIMigrationOpenStack=true|false (BETA - 默认值=false) CSIMigrationOpenStackComplete=true|false (ALPHA - 默认值=false) CSIMigrationvSphere=true|false (BETA - 默认值=false) CSIMigrationvSphereComplete=true|false (BETA - 默认值=false) CSIStorageCapacity=true|false (ALPHA - 默认值=false) CSIVolumeFSGroupPolicy=true|false (ALPHA - 默认值=false) ConfigurableFSGroupPolicy=true|false (ALPHA - 默认值=false) CustomCPUCFSQuotaPeriod=true|false (ALPHA - 默认值=false) DefaultPodTopologySpread=true|false (ALPHA - 默认值=false) DevicePlugins=true|false (BETA - 默认值=true) DisableAcceleratorUsageMetrics=true|false (ALPHA - 默认值=false) DynamicKubeletConfig=true|false (BETA - 默认值=true) EndpointSlice=true|false (BETA - 默认值=true) EndpointSliceProxying=true|false (BETA - 默认值=true) EphemeralContainers=true|false (ALPHA - 默认值=false) ExpandCSIVolumes=true|false (BETA - 默认值=true) ExpandInUsePersistentVolumes=true|false (BETA - 默认值=true) ExpandPersistentVolumes=true|false (BETA - 默认值=true) ExperimentalHostUserNamespace默认值ing=true|false (BETA - 默认值=false) GenericEphemeralVolume=true|false (ALPHA - 默认值=false) HPAScaleToZero=true|false (ALPHA - 默认值=false) HugePageStorageMediumSize=true|false (BETA - 默认值=true) HyperVContainer=true|false (ALPHA - 默认值=false) IPv6DualStack=true|false (ALPHA - 默认值=false) ImmutableEphemeralVolumes=true|false (BETA - 默认值=true) KubeletPodResources=true|false (BETA - 默认值=true) LegacyNodeRoleBehavior=true|false (BETA - 默认值=true) LocalStorageCapacityIsolation=true|false (BETA - 默认值=true) LocalStorageCapacityIsolationFSQuotaMonitoring=true|false (ALPHA - 默认值=false) NodeDisruptionExclusion=true|false (BETA - 默认值=true) NonPreemptingPriority=true|false (BETA - 默认值=true) PodDisruptionBudget=true|false (BETA - 默认值=true) PodOverhead=true|false (BETA - 默认值=true) ProcMountType=true|false (ALPHA - 默认值=false) QOSReserved=true|false (ALPHA - 默认值=false) RemainingItemCount=true|false (BETA - 默认值=true) RemoveSelfLink=true|false (ALPHA - 默认值=false) RotateKubeletServerCertificate=true|false (BETA - 默认值=true) RunAsGroup=true|false (BETA - 默认值=true) RuntimeClass=true|false (BETA - 默认值=true) SCTPSupport=true|false (BETA - 默认值=true) SelectorIndex=true|false (BETA - 默认值=true) ServerSideApply=true|false (BETA - 默认值=true) ServiceAccountIssuerDiscovery=true|false (ALPHA - 默认值=false) ServiceAppProtocol=true|false (BETA - 默认值=true) ServiceNodeExclusion=true|false (BETA - 默认值=true) ServiceTopology=true|false (ALPHA - 默认值=false) SetHostnameAsFQDN=true|false (ALPHA - 默认值=false) StartupProbe=true|false (BETA - 默认值=true) StorageVersionHash=true|false (BETA - 默认值=true) SupportNodePidsLimit=true|false (BETA - 默认值=true) SupportPodPidsLimit=true|false (BETA - 默认值=true) Sysctls=true|false (BETA - 默认值=true) TTLAfterFinished=true|false (ALPHA - 默认值=false) TokenRequest=true|false (BETA - 默认值=true) TokenRequestProjection=true|false (BETA - 默认值=true) TopologyManager=true|false (BETA - 默认值=true) ValidateProxyRedirects=true|false (BETA - 默认值=true) VolumeSnapshotDataSource=true|false (BETA - 默认值=true) WarningHeaders=true|false (BETA - 默认值=true) WinDSR=true|false (ALPHA - 默认值=false) WinOverlay=true|false (ALPHA - 默认值=false) WindowsEndpointSliceProxying=true|false (ALPHA - 默认值=false) --healthz-bind-address 0.0.0.0 默认值: 0.0.0.0:10256 服务健康检查的 IP 地址和端口(对于所有 IPv4 接口设置为 '0.0.0.0:10256',对于所有 IPv6 接口设置为 '[::]:10256')
设置为空则禁用。 --healthz-bind-address 0.0.0.0 默认值: 0.0.0.0:10256 服务健康检查的 IP 地址和端口(设置为 0.0.0.0 表示使用所有 IPv4 接口,设置为 :: 表示使用所有 IPv6 接口) -h, --help kube-proxy 操作的帮助命令 --hostname-override string 如果非空,将使用此字符串作为标识而不是实际的主机名。 --iptables-masquerade-bit int32 默认值: 14 如果使用纯 iptables 代理,则 fwmark 空间的 bit 用于标记需要 SNAT 的数据包。必须在 [0,31] 范围内。 --iptables-min-sync-period duration 默认值:1s iptables 规则可以随着端点和服务的更改而刷新的最小间隔(例如 '5s'、'1m'、'2h22m')。 --iptables-sync-period duration 默认值: 30s 刷新 iptables 规则的最大间隔(例如 '5s'、'1m'、'2h22m')。必须大于 0。 --ipvs-exclude-cidrs stringSlice 逗号分隔的 CIDR 列表,ipvs 代理在清理 IPVS 规则时不应使用此列表。 --ipvs-min-sync-period duration ipvs 规则可以随着端点和服务的更改而刷新的最小间隔(例如 '5s'、'1m'、'2h22m')。 --ipvs-scheduler string 代理模式为 ipvs 时的 ipvs 调度器类型 --ipvs-strict-arp 通过将 arp_ignore 设置为 1 并将 arp_announce 设置为 2 启用严格的 ARP --ipvs-sync-period duration 默认值: 30s 刷新 ipvs 规则的最大间隔(例如 '5s'、'1m'、'2h22m')。必须大于 0。 --ipvs-tcp-timeout duration 空闲 IPVS TCP 连接的超时时间,0 保持连接(例如 '5s'、'1m'、'2h22m')。 --ipvs-tcpfin-timeout duration 收到 FIN 数据包后,IPVS TCP 连接的超时,0 保持连接不变(例如 '5s'、'1m'、'2h22m')。 --ipvs-udp-timeout duration IPVS UDP 数据包的超时,0 保持连接不动(例如 '5s'、'1m'、'2h22m')。 --kube-api-burst int32 默认值: 10 与 kubernetes apiserver 通信的数量 --kube-api-content-type string 默认值: "application/vnd.kubernetes.protobuf" 发送到 apiserver 的请求的内容类型。 --kube-api-qps float32 默认值: 5 与 kubernetes apiserver 交互时使用的 QPS --kubeconfig string 包含授权信息的 kubeconfig 文件的路径(master 位置由 master 标志设置)。 --log-flush-frequency duration 默认值: 5s 两次日志刷新之间的最大秒数 --masquerade-all 如果使用纯 iptables 代理,则对通过服务集群 IP 发送的所有流量进行 SNAT(通常不需要) --master string Kubernetes API 服务器的地址(覆盖 kubeconfig 中的任何值) --metrics-bind-address ipport 0.0.0.0 默认值: 127.0.0.1:10249 metrics 服务器要使用的 IP 地址和端口
(设置为 '0.0.0.0:10249' 则使用 IPv4 接口,设置为 '[::]:10249' 则使用所有 IPv6 接口)
设置为空则禁用。 --metrics-port int32 默认值: 10249 绑定 metrics 服务器的端口。使用 0 表示禁用。 --nodeport-addresses stringSlice 一个字符串值,指定用于 NodePorts 的地址。值可以是有效的 IP 块(例如 1.2.3.0/24, 1.2.3.4/32)。默认的空字符串切片([])表示使用所有本地地址。 --oom-score-adj int32 默认值: -999 kube-proxy 进程中的 oom-score-adj 值必须在 [-1000,1000] 范围内 --profiling 如果为 true,则通过 Web 接口 /debug/pprof 启用性能分析。 --proxy-mode ProxyMode 使用哪种代理模式:'userspace'(较旧)或 'iptables'(较快)或 'ipvs'(实验)。如果为空,使用最佳可用代理(当前为 iptables)。如果选择了 iptables 代理,无论如何,但系统的内核或 iptables 版本较低,这总是会回退到用户空间代理。 --proxy-port-range port-range 可以使用代理服务流量的主机端口(包括 beginPort-endPort、single port、beginPort+offset)的范围。如果(未指定,0 或 0-0)则随机选择端口。 --show-hidden-metrics-for-version string 你要显示隐藏指标的先前版本。
仅先前的次要版本有意义,不允许其他值。
格式为 <major>.<minor> ,例如:'1.16'。
这种格式的目的是确保你有机会注意到下一个发行版是否隐藏了其他指标,
而不是在之后将其永久删除时感到惊讶。 --udp-timeout duration 默认值: 250ms 空闲 UDP 连接将保持打开的时长(例如 '250ms','2s')。必须大于 0。仅适用于 proxy-mode=userspace --version version[=true] 打印版本信息并退出 --write-config-to string 如果设置,将配置值写入此文件并退出。
6.9.6 - kube-scheduler 简介 Kubernetes 调度器是一个控制面进程,负责将 Pods 指派到节点上。
调度器基于约束和可用资源为调度队列中每个 Pod 确定其可合法放置的节点。
调度器之后对所有合法的节点进行排序,将 Pod 绑定到一个合适的节点。
在同一个集群中可以使用多个不同的调度器;kube-scheduler 是其参考实现。
参阅调度
以获得关于调度和 kube-scheduler 组件的更多信息。
kube-scheduler [flags]
选项 --add-dir-header 如果为 true,则将文件目录添加到日志消息的头部 --address string 默认值:"0.0.0.0" 已弃用: 要监听 --port 端口的 IP 地址(对于所有 IPv4 接口设置为 0.0.0.0,对于所有 IPv6 接口设置为 ::)。
请参阅 --bind-address。 --algorithm-provider string 已弃用: 要使用的调度算法驱动,此标志设置组件配置框架的默认插件。
可选值:ClusterAutoscalerProvider | DefaultProvider --alsologtostderr --authentication-kubeconfig string 指向具有足够权限以创建 tokenaccessreviews.authentication.k8s.io 的
Kubernetes 核心服务器的 kubeconfig 文件。
这是可选的。如果为空,则所有令牌请求均被视为匿名请求,并且不会在集群中查找任何客户端 CA。 --authentication-skip-lookup 如果为 false,则 authentication-kubeconfig 将用于从集群中查找缺少的身份验证配置。 --authentication-token-webhook-cache-ttl duration 默认值:10s 缓存来自 Webhook 令牌身份验证器的响应的持续时间。 --authentication-tolerate-lookup-failure 默认值:true 如果为 true,则无法从集群中查找缺少的身份验证配置是致命的。
请注意,这可能导致身份验证将所有请求视为匿名。 --authorization-always-allow-paths stringSlice 默认值:[/healthz] 在授权过程中跳过的 HTTP 路径列表,即在不联系 'core' kubernetes 服务器的情况下被授权的 HTTP 路径。 --authorization-kubeconfig string 指向具有足够权限以创建 subjectaccessreviews.authorization.k8s.io 的
Kubernetes 核心服务器的 kubeconfig 文件。这是可选的。
如果为空,则所有未被鉴权机制略过的请求都会被禁止。 --authorization-webhook-cache-authorized-ttl duration 默认值:10s 缓存来自 Webhook 授权者的 'authorized' 响应的持续时间。 --authorization-webhook-cache-unauthorized-ttl duration 默认值:10s 缓存来自 Webhook 授权者的 'unauthorized' 响应的持续时间。 --azure-container-registry-config string 包含 Azure 容器仓库配置信息的文件的路径。 --bind-address ip 默认值:0.0.0.0 监听 --secure-port 端口的 IP 地址。
集群的其余部分以及 CLI/ Web 客户端必须可以访问关联的接口。
如果为空,将使用所有接口(0.0.0.0 表示使用所有 IPv4 接口,"::" 表示使用所有 IPv6 接口)。 --cert-dir string TLS 证书所在的目录。如果提供了--tls-cert-file 和 --tls private-key-file,
则将忽略此参数。 --client-ca-file string 如果已设置,由 client-ca-file 中的证书机构签名的客户端证书的任何请求都将使用
与客户端证书的 CommonName 对应的身份进行身份验证。 --config string 配置文件的路径。以下标志会覆盖此文件中的值: --address --port --use-legacy-policy-config --policy-configmap --policy-config-file --algorithm-provider --contention-profiling 已弃用: 如果启用了性能分析,则启用锁竞争分析 --experimental-logging-sanitization [试验性功能] 当启用此标志时,标记为敏感的字段(密码、密钥、令牌)等不会被日志
输出。 运行时的日志清理操作可能引入相当程度的计算开销,因此不应在生产环境中启用。 --feature-gates mapStringBool 一组 key=value 对,描述了 alpha/experimental 特征开关。选项包括: APIListChunking=true|false (BETA - 默认值=true) APIPriorityAndFairness=true|false (BETA - 默认值=true) APIResponseCompression=true|false (BETA - 默认值=true) APIServerIdentity=true|false (ALPHA - 默认值=false) AllAlpha=true|false (ALPHA - 默认值=false) AllBeta=true|false (BETA - 默认值=false) AllowInsecureBackendProxy=true|false (BETA - 默认值=true) AnyVolumeDataSource=true|false (ALPHA - 默认值=false) AppArmor=true|false (BETA - 默认值=true) BalanceAttachedNodeVolumes=true|false (ALPHA - 默认值=false) BoundServiceAccountTokenVolume=true|false (ALPHA - 默认值=false) CPUManager=true|false (BETA - 默认值=true) CRIContainerLogRotation=true|false (BETA - 默认值=true) CSIInlineVolume=true|false (BETA - 默认值=true) CSIMigration=true|false (BETA - 默认值=true) CSIMigrationAWS=true|false (BETA - 默认值=true) CSIMigrationAWSComplete=true|false (ALPHA - 默认值=false) CSIMigrationAzureDisk=true|false (BETA - 默认值=true) CSIMigrationAzureDiskComplete=true|false (ALPHA - 默认值=false) CSIMigrationAzureFile=true|false (ALPHA - 默认值=false) CSIMigrationAzureFileComplete=true|false (ALPHA - 默认值=false) CSIMigrationGCE=true|false (BETA - 默认值=true) CSIMigrationGCEComplete=true|false (ALPHA - 默认值=false) CSIMigrationOpenStack=true|false (BETA - 默认值=true) CSIMigrationOpenStackComplete=true|false (ALPHA - 默认值=false) CSIMigrationvSphere=true|false (BETA - 默认值=false) CSIMigrationvSphereComplete=true|false (BETA - default=false) CSIServiceAccountToken=true|false (ALPHA - 默认值=false) CSIStorageCapacity=true|false (ALPHA - 默认值=false) CSIVolumeFSGroupPolicy=true|false (BETA - 默认值=true) ConfigurableFSGroupPolicy=true|false (BETA - 默认值=true) CronJobControllerV2=true|false (ALPHA - 默认值=false) CustomCPUCFSQuotaPeriod=true|false (ALPHA - 默认值=false) DefaultPodTopologySpread=true|false (BETA - 默认值=true) DevicePlugins=true|false (BETA - 默认值=true) DisableAcceleratorUsageMetrics=true|false (BETA - 默认值=true) DownwardAPIHugePages=true|false (ALPHA - 默认值=false) DynamicKubeletConfig=true|false (BETA - 默认值=true) EfficientWatchResumption=true|false (ALPHA - 默认值=false) EndpointSlice=true|false (ALPHA - 默认值=false) EndpointSliceNodeName=true|false (ALPHA - 默认值=false) EndpointSliceProxying=true|false (BETA - 默认值=true) EndpointSliceTerminatingCondition=true|false (ALPHA - 默认值=false) EphemeralContainers=true|false (ALPHA - 默认值=false) ExpandCSIVolumes=true|false (BETA - 默认值=true) ExpandInUsePersistentVolumes=true|false (BETA - 默认值=true) ExpandPersistentVolumes=true|false (BETA - 默认值=true) ExperimentalHostUserNamespaceDefaulting=true|false (BETA - 默认值=false) GenericEphemeralVolume=true|false (ALPHA - 默认值=false) GracefulNodeShutdown=true|false (ALPHA - 默认值=false) HPAContainerMetrics=true|false (ALPHA - 默认值=false) HPAScaleToZero=true|false (ALPHA - 默认值=false) HugePageStorageMediumSize=true|false (BETA - 默认值=true) IPv6DualStack=true|false (ALPHA - 默认值=false) ImmutableEphemeralVolumes=true|false (BETA - 默认值=true) KubeletCredentialProviders=true|false (ALPHA - 默认值=false) KubeletPodResources=true|false (BETA - 默认值=true) LegacyNodeRoleBehavior=true|false (BETA - 默认值=true) LocalStorageCapacityIsolation=true|false (BETA - 默认值=true) LocalStorageCapacityIsolationFSQuotaMonitoring=true|false (ALPHA - 默认值=false) MixedProtocolLBService=true|false (ALPHA - 默认值=false) NodeDisruptionExclusion=true|false (BETA - 默认值=false) NonPreemptingPriority=true|false (BETA - 默认值=true) PodDisruptionBudget=true|false (BETA - 默认值=true) PodOverhead=true|false (BETA - 默认值=true) ProcMountType=true|false (ALPHA - 默认值=false) QOSReserved=true|false (ALPHA - 默认值=false) RemainingItemCount=true|false (BETA - 默认值=true) RemoveSelfLink=true|false (BETA - 默认值=true) RootCAConfigMap=true|false (BETA - 默认值=true) RotateKubeletServerCertificate=true|false (BETA - 默认值=true) RunAsGroup=true|false (BETA - 默认值=true) ServerSideApply=true|false (BETA - 默认值=true) ServiceAccountIssuerDiscovery=true|false (BETA - 默认值=true) ServiceLBNodePortControl=true|false (ALPHA - 默认值=false) ServiceNodeExclusion=true|false (BETA - 默认值=true) ServiceTopology=true|false (ALPHA - 默认值=false) SetHostnameAsFQDN=true|false (BETA - 默认值=true) SizeMemoryBackedVolumes=true|false (ALPHA - 默认值=false) StorageVersionAPI=true|false (ALPHA - 默认值=false) StorageVersionHash=true|false (BETA - 默认值=true) Sysctls=true|false (BETA - 默认值=true) TTLAfterFinished=true|false (ALPHA - 默认值=false) TopologyManager=true|false (BETA - 默认值=true) ValidateProxyRedirects=true|false (BETA - 默认值=true) WarningHeaders=true|false (BETA - 默认值=true) WinDSR=true|false (ALPHA - 默认值=false) WinOverlay=true|false (BETA - 默认值=true) WindowsEndpointSliceProxying=true|false (ALPHA - 默认值=false) --hard-pod-affinity-symmetric-weight int32 默认值:1 已弃用: RequiredDuringScheduling 亲和性是不对称的,但是存在与每个
RequiredDuringScheduling 关联性规则相对应的隐式 PreferredDuringScheduling 关联性规则。
--hard-pod-affinity-symmetric-weight 代表隐式 PreferredDuringScheduling
关联性规则的权重。权重必须在 0-100 范围内。此选项已移至策略配置文件。 -h, --help kube-scheduler 帮助命令 --http2-max-streams-per-connection int 服务器为客户端提供的 HTTP/2 连接最大限制。零表示使用 Golang 的默认值。 --kube-api-burst int32 默认值:100 已弃用: 与 kubernetes API 通信时使用的突发请求个数限值。 --kube-api-content-type string 默认值:"application/vnd.kubernetes.protobuf" 已弃用: 发送到 API 服务器的请求的内容类型。 --kube-api-qps float32 默认值:50 已弃用: 与 kubernetes apiserver 通信时要使用的 QPS --kubeconfig string 已弃用: 包含鉴权和主节点位置信息的 kubeconfig 文件的路径。 --leader-elect 默认值:true 在执行主循环之前,开始领导者选举并选出领导者。
使用多副本来实现高可用性时,可启用此标志。 --leader-elect-lease-duration duration 默认值:15s 非领导者候选人在观察到领导者更新后将等待直到试图获得领导但未更新的领导者职位的等待时间。
这实际上是领导者在被另一位候选人替代之前可以停止的最大持续时间。
该情况仅在启用了领导者选举的情况下才适用。 --leader-elect-renew-deadline duration 默认值:10s 领导者尝试在停止领导之前更新领导职位的间隔时间。该时间必须小于或等于租赁期限。
仅在启用了领导者选举的情况下才适用。 --leader-elect-resource-lock endpoints 默认值:"leases" 在领导者选举期间用于锁定的资源对象的类型。支持的选项是 `endpoints`、
`configmaps`、`leases`、`endpointleases` 和 `configmapsleases`。 --leader-elect-resource-name string 默认值:"kube-scheduler" 在领导者选举期间用于锁定的资源对象的名称。 --leader-elect-resource-namespace string 默认值:"kube-system" 在领导者选举期间用于锁定的资源对象的命名空间。 --leader-elect-retry-period duration 默认值:2s 客户应在尝试获取和更新领导之间等待的时间。仅在启用了领导者选举的情况下才适用。 --lock-object-name string 默认值:"kube-scheduler" 已弃用: 定义锁对象的名称。将被删除以便使用 --leader-elect-resource-name。 --lock-object-namespace string 默认值:"kube-system" 已弃用: 定义锁对象的命名空间。将被删除以便使用 leader-elect-resource-namespace。 --log-backtrace-at traceLocation 默认值::0 当记录命中行文件 file 的第 N 行时输出堆栈跟踪。 --log-dir string 如果为非空,则在此目录中写入日志文件。 --log-file string 如果为非空,则使用此文件作为日志文件。 --log-file-max-size uint 默认值:1800 定义日志文件可以增长到的最大值。单位为兆字节。
如果值为 0,则最大文件大小为无限制。 --log-flush-frequency duration 默认值:5s 两次日志刷新之间的最大秒数。 --logging-format string 默认值:"text" 设置日志格式。可选格式:"json"、"text"。 非默认格式不会在意以下标志设置:
--add_dir_header、--alsologtostderr、--log_backtrace_at、--log_dir、
--log_file、--log_file_max_size、--logtostderr、--one_output、
--skip_headers、--skip_log_headers、--stderrthreshold、--vmodule、
--log-flush-frequency. 非默认选项目前处于 Alpha 阶段,有可能会出现变更且无事先警告。 --logtostderr 默认值:true 日志记录到标准错误输出而不是文件。 --master string Kubernetes API 服务器的地址(覆盖 kubeconfig 中的任何值)。 --one-output 若此标志为 true,则日志仅写入其自身的严重性级别,而不会写入所有较低严重性级别。 --permit-port-sharing 如果此标志为 true,在绑定端口时会使用 SO_REUSEPORT,从而允许不止一个
实例绑定到同一地址和端口。 --policy-config-file string 已弃用:包含调度器策略配置的文件。
当策略 ConfigMap 为提供时,或者 --use-legacy-policy-config=true 时使用此文件。
注意:当此标志与插件配置一起使用时,调度器会失败。 --policy-configmap string 已弃用: 包含调度器策略配置的 ConfigMap 对象的名称。
如果 --use-legacy-policy-config=false,则它必须在调度器初始化之前存在于
系统命名空间中。配置数据必须对应 'data' 映射中键名为 'policy.cfg' 的元素的值。
注意:如果与插件配置一起使用,调度器会失败。 --policy-configmap-namespace string 默认值:"kube-system" 已弃用: 策略 ConfigMap 所在的名字空间。如果未提供或为空,则将使用 kube-system 名字空间。
注意:如果与插件配置一起使用,调度器会失败。 --port int 默认值:10251 已弃用: 在没有身份验证和授权的情况下不安全地为 HTTP 服务的端口。
如果为0,则根本不提供 HTTP。请参见--secure-port。 --profiling 已弃用: 通过 Web 界面主机启用配置文件:host:port/debug/pprof/。 --requestheader-allowed-names stringSlice 客户端证书通用名称列表,允许在 --requestheader-username-headers
指定的头部中提供用户名。如果为空,则允许任何由
--requestheader-client-ca-file 中证书机构验证的客户端证书。 --requestheader-client-ca-file string 在信任 --requestheader-username-headers 指定的头部中的用户名之前
用于验证传入请求上的客户端证书的根证书包。
警告:通常不应假定传入请求已经完成鉴权。 --requestheader-extra-headers-prefix stringSlice 默认值:[x-remote-extra-] 要检查请求头部前缀列表。建议使用 X-Remote-Extra-。 --requestheader-group-headers stringSlice 默认值:[x-remote-group] 用于检查组的请求头部列表。建议使用 X-Remote-Group。 --requestheader-username-headers stringSlice 默认值:[x-remote-user] 用于检查用户名的请求头部列表。X-Remote-User 很常用。 --scheduler-name string 默认值:"default-scheduler" 已弃用: 调度器名称,用于根据 Pod 的 "spec.schedulerName" 选择此
调度器将处理的 Pod。 --secure-port int 默认值:10259 通过身份验证和授权为 HTTPS 服务的端口。如果为 0,则根本不提供 HTTPS。 --show-hidden-metrics-for-version string 你希望显式隐藏指标的老版本号。只有较早的此版本号有意义,其它值都是不允许的。
格式为 <主版本>.<此版本>,例如:'1.16'。
此格式的目的是确保你有机会注意到是否下一个发行版本中隐藏了一些额外的指标,
而不是当某些指标在该版本之后被彻底移除时感到震惊。 --skip-headers 如果为 true,日志消息中不再写入头部前缀。 --skip-log-headers 如果为 true,则在打开日志文件时忽略其头部。 --stderrthreshold severity 默认值:2 达到或超过此阈值的日志会被写入到标准错误输出。 --tls-cert-file string 包含默认的 HTTPS x509 证书的文件。(CA证书(如果有)在服务器证书之后并置)。
如果启用了 HTTPS 服务,并且未提供 --tls-cert-file 和
--tls-private-key-file,则会为公共地址生成一个自签名证书和密钥,
并将其保存到 --cert-dir 指定的目录中。 --tls-cipher-suites stringSlice 服务器的密码套件列表,以逗号分隔。如果省略,将使用默认的 Go 密码套件。
优先考虑的值:
TLS_AES_128_GCM_SHA256, TLS_AES_256_GCM_SHA384, TLS_CHACHA20_POLY1305_SHA256, TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305, TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305, TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, TLS_RSA_WITH_3DES_EDE_CBC_SHA, TLS_RSA_WITH_AES_128_CBC_SHA, TLS_RSA_WITH_AES_128_GCM_SHA256, TLS_RSA_WITH_AES_256_CBC_SHA, TLS_RSA_WITH_AES_256_GCM_SHA384. 不安全的值:
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, TLS_ECDHE_RSA_WITH_RC4_128_SHA, TLS_RSA_WITH_AES_128_CBC_SHA256, TLS_RSA_WITH_RC4_128_SHA. --tls-min-version string 支持的最低 TLS 版本。可能的值:VersionTLS10, VersionTLS11, VersionTLS12, VersionTLS13 --tls-private-key-file string 包含与 --tls-cert-file 匹配的默认 x509 私钥的文件。 --tls-sni-cert-key namedCertKey 默认值:[] 一对 x509 证书和私钥文件路径,可选地后缀为完全限定域名的域模式列表,
并可能带有前缀的通配符段。如果未提供域名模式,则提取证书名称。
非通配符匹配优先于通配符匹配,显式域名模式优先于提取而来的名称。
若有多个密钥/证书对,可多次使用 --tls-sni-cert-key。
例如: "example.crt,example.key" 或者 "foo.crt,foo.key:*.foo.com,foo.com"。 --use-legacy-policy-config 已弃用:设置为 true 时,调度程序将忽略策略 ConfigMap 并使用策略配置文件。
注意:当此标志与插件配置一起使用时,调度器会失败。 -v, --v Level 设置日志级别详细程度的数字 --version version[=true] 打印版本信息并退出。 --vmodule moduleSpec 以逗号分隔的 pattern=N 设置列表,用于文件过滤的日志记录。 --write-config-to string 如果已设置,将配置值写入此文件并退出。
6.9.7 - Kubelet 认证/鉴权 概述 kubelet 的 HTTPS 端点公开了 API,
这些 API 可以访问敏感度不同的数据,
并允许你在节点上和容器内以不同级别的权限执行操作。
本文档介绍了如何对 kubelet 的 HTTPS 端点的访问进行认证和鉴权。
Kubelet 身份认证 默认情况下,未被已配置的其他身份认证方法拒绝的对 kubelet 的 HTTPS 端点的请求会被视为匿名请求,
并被赋予 system:anonymous 用户名和 system:unauthenticated 组。
要禁用匿名访问并向未经身份认证的请求发送 401 Unauthorized 响应,请执行以下操作:
带 --anonymous-auth=false 标志启动 kubelet 要对 kubelet 的 HTTPS 端点启用 X509 客户端证书认证:
带 --client-ca-file 标志启动 kubelet,提供一个 CA 证书包以供验证客户端证书 带 --kubelet-client-certificate 和 --kubelet-client-key 标志启动 apiserver 有关更多详细信息,请参见
apiserver 身份验证文档 要启用 API 持有者令牌(包括服务帐户令牌)以对 kubelet 的 HTTPS 端点进行身份验证,请执行以下操作:
确保在 API 服务器中启用了 authentication.k8s.io/v1beta1 API 组 带 --authentication-token-webhook 和 --kubeconfig 标志启动 kubelet kubelet 调用已配置的 API 服务器上的 TokenReview API,以根据持有者令牌确定用户信息 Kubelet 鉴权 任何成功通过身份验证的请求(包括匿名请求)之后都会被鉴权。
默认的鉴权模式为 AlwaysAllow,它允许所有请求。
细分对 kubelet API 的访问权限可能有多种原因:
启用了匿名身份验证,但是应限制匿名用户调用 kubelet API 的能力 启用了持有者令牌认证,但应限制任意 API 用户(如服务帐户)调用 kubelet API 的能力 启用了客户端证书身份验证,但仅应允许已配置的 CA 签名的某些客户端证书使用 kubelet API 要细分对 kubelet API 的访问权限,请将鉴权委派给 API 服务器:
确保在 API 服务器中启用了 authorization.k8s.io/v1beta1 API 组 带 --authorization-mode=Webhook 和 --kubeconfig 标志启动 kubelet kubelet 调用已配置的 API 服务器上的 SubjectAccessReview API,
以确定每个请求是否得到鉴权 kubelet 使用与 apiserver 相同的
请求属性
方法对 API 请求执行鉴权。
请求的动词根据传入请求的 HTTP 动词确定:
HTTP 动词 请求动词 POST create GET, HEAD get PUT update PATCH patch DELETE delete
资源和子资源是根据传入请求的路径确定的:
Kubelet API 资源 子资源 /stats/* nodes stats /metrics/* nodes metrics /logs/* nodes log /spec/* nodes spec 其它所有 nodes proxy
名字空间和 API 组属性始终是空字符串,
资源名称始终是 kubelet 的 Node API 对象的名称。
在此模式下运行时,请确保传递给 apiserver 的由 --kubelet-client-certificate 和
--kubelet-client-key 标志标识的用户具有以下属性的鉴权:
verb=*, resource=nodes, subresource=proxy verb=*, resource=nodes, subresource=stats verb=*, resource=nodes, subresource=log verb=*, resource=nodes, subresource=spec verb=*, resource=nodes, subresource=metrics 6.9.8 - TLS 启动引导 在一个 Kubernetes 集群中,工作节点上的组件(kubelet 和 kube-proxy)需要与
Kubernetes 主控组件通信,尤其是 kube-apiserver。
为了确保通信本身是私密的、不被干扰,并且确保集群的每个组件都在与另一个
可信的组件通信,我们强烈建议使用节点上的客户端 TLS 证书。
启动引导这些组件的正常过程,尤其是需要证书来与 kube-apiserver 安全通信的
工作节点,可能会是一个具有挑战性的过程,因为这一过程通常不受 Kubernetes 控制,
需要不少额外工作。
这也使得初始化或者扩缩一个集群的操作变得具有挑战性。
为了简化这一过程,从 1.4 版本开始,Kubernetes 引入了一个证书请求和签名
API 以便简化此过程。该提案可在
这里 看到。
本文档描述节点初始化的过程,如何为 kubelet 配置 TLS 客户端证书启动引导,
以及其背后的工作原理。
初始化过程 当工作节点启动时,kubelet 执行以下操作:
寻找自己的 kubeconfig 文件 检索 API 服务器的 URL 和凭据,通常是来自 kubeconfig 文件中的
TLS 密钥和已签名证书 尝试使用这些凭据来与 API 服务器通信 假定 kube-apiserver 成功地认证了 kubelet 的凭据数据,它会将 kubelet 视为
一个合法的节点并开始将 Pods 分派给该节点。
注意,签名的过程依赖于:
kubeconfig 中包含密钥和本地主机的证书证书被 kube-apiserver 所信任的一个证书机构(CA)所签名 负责部署和管理集群的人有以下责任:
创建 CA 密钥和证书 将 CA 证书发布到 kube-apiserver 运行所在的主控节点上 为每个 kubelet 创建密钥和证书;强烈建议为每个 kubelet 使用独一无二的、
CN 取值与众不同的密钥和证书 使用 CA 密钥对 kubelet 证书签名 将 kubelet 密钥和签名的证书发布到 kubelet 运行所在的特定节点上 本文中描述的 TLS 启动引导过程有意简化甚至完全自动化上述过程,尤其是
第三步之后的操作,因为这些步骤是初始化或者扩缩集群时最常见的操作。
启动引导初始化 在启动引导初始化过程中,会发生以下事情:
kubelet 启动 kubelet 看到自己 没有 对应的 kubeconfig 文件 kubelet 搜索并发现 bootstrap-kubeconfig 文件 kubelet 读取该启动引导文件,从中获得 API 服务器的 URL 和用途有限的
一个“令牌(Token)” kubelet 建立与 API 服务器的连接,使用上述令牌执行身份认证 kubelet 现在拥有受限制的凭据来创建和取回证书签名请求(CSR) kubelet 为自己创建一个 CSR,并将其 signerName 设置为 kubernetes.io/kube-apiserver-client-kubelet CSR 被以如下两种方式之一批复: 如果配置了,kube-controller-manager 会自动批复该 CSR 如果配置了,一个外部进程,或者是人,使用 Kubernetes API 或者使用 kubectl
来批复该 CSR kubelet 所需要的证书被创建 证书被发放给 kubelet kubelet 取回该证书 kubelet 创建一个合适的 kubeconfig,其中包含密钥和已签名的证书 kubelet 开始正常操作 可选地,如果配置了,kubelet 在证书接近于过期时自动请求更新证书 更新的证书被批复并发放;取决于配置,这一过程可能是自动的或者手动完成 本文的其余部分描述配置 TLS 启动引导的必要步骤及其局限性。
配置 要配置 TLS 启动引导及可选的自动批复,你必须配置以下组件的选项:
kube-apiserver kube-controller-manager kubelet 集群内的资源:ClusterRoleBinding 以及可能需要的 ClusterRole 此外,你需要有 Kubernetes 证书机构(Certificate Authority,CA)。
证书机构 就像在没有启动引导的情况下,你会需要证书机构(CA)密钥和证书。
这些数据会被用来对 kubelet 证书进行签名。
如前所述,将证书机构密钥和证书发布到主控节点是你的责任。
就本文而言,我们假定这些数据被发布到主控节点上的
/var/lib/kubernetes/ca.pem(证书)和
/var/lib/kubernetes/ca-key.pem(密钥)文件中。
我们将这两个文件称作“Kubernetes CA 证书和密钥”。
所有 Kubernetes 组件(kubelet、kube-apiserver、kube-controller-manager)都使用
这些凭据,并假定这里的密钥和证书都是 PEM 编码的。
kube-apiserver 配置 启用 TLS 启动引导对 kube-apiserver 有若干需求:
能够识别对客户端证书进行签名的 CA 能够对启动引导的 kubelet 执行身份认证,并将其置入 system:bootstrappers 组 能够对启动引导的 kubelet 执行鉴权操作,允许其创建证书签名请求(CSR) 识别客户证书 对于所有客户端证书的认证操作而言,这是很常见的。
如果还没有设置,要为 kube-apiserver 命令添加 --client-ca-file=FILENAME
标志来启用客户端证书认证,在标志中引用一个包含用来签名的证书的证书机构包,
例如:--client-ca-file=/var/lib/kubernetes/ca.pem。
初始启动引导认证 为了让启动引导的 kubelet 能够连接到 kube-apiserver 并请求证书,
它必须首先在服务器上认证自身身份。你可以使用任何一种能够对 kubelet 执行身份认证的
身份认证组件 。
尽管所有身份认证策略都可以用来对 kubelet 的初始启动凭据来执行认证,
出于容易准备的因素,建议使用如下两个身份认证组件:
启动引导令牌(Bootstrap Token) 令牌认证文件 启动引导令牌是一种对 kubelet 进行身份认证的方法,相对简单且容易管理,
且不需要在启动 kube-apiserver 时设置额外的标志。
启动引导令牌从 Kubernetes 1.12 开始是一种 Beta 功能特性。
无论选择哪种方法,这里的需求是 kubelet 能够被身份认证为某个具有如下权限的用户:
创建和读取 CSR 在启用了自动批复时,能够在请求节点客户端证书时得到自动批复 使用启动引导令牌执行身份认证的 kubelet 会被认证为 system:bootstrappers
组中的用户。这是使用启动引导令牌的一种标准方法。
随着这个功能特性的逐渐成熟,你需要确保令牌绑定到某基于角色的的访问控制(RBAC)
策略上,从而严格限制请求(使用启动引导令牌 )
仅限于客户端申请提供证书。当 RBAC 被配置启用时,可以将令牌限制到某个组,从而
提高灵活性。例如,你可以在准备节点期间禁止某特定启动引导组的访问。
启动引导令牌 启动引导令牌的细节在这里
详述。启动引导令牌在 Kubernetes 集群中存储为 Secret 对象,被发放给各个 kubelet。
你可以在整个集群中使用同一个令牌,也可以为每个节点发放单独的令牌。
这一过程有两个方面:
基于令牌 ID、机密数据和范畴信息创建 Kubernetes Secret 将令牌发放给 kubelet 从 kubelet 的角度,所有令牌看起来都很像,没有特别的含义。
从 kube-apiserver 服务器的角度,启动引导令牌是很特殊的。
根据其 type、namespace 和 name,kube-apiserver 能够将认作特殊的令牌,
并授予携带该令牌的任何人特殊的启动引导权限,换言之,将其视为
system:bootstrappers 组的成员。这就满足了 TLS 启动引导的基本需求。
关于创建 Secret 的进一步细节可访问这里 。
如果你希望使用启动引导令牌,你必须在 kube-apiserver 上使用下面的标志启用之:
--enable-bootstrap-token-auth=true
令牌认证文件 kube-apiserver 能够将令牌视作身份认证依据。
这些令牌可以是任意数据,但必须表示为基于某安全的随机数生成器而得到的
至少 128 位混沌数据。这里的随机数生成器可以是现代 Linux 系统上的
/dev/urandom。生成令牌的方式有很多种。例如:
head -c 16 /dev/urandom | od -An -t x | tr -d ' '
上面的命令会生成类似于 02b50b05283e98dd0fd71db496ef01e8 这样的令牌。
令牌文件看起来是下面的例子这样,其中前面三个值可以是任何值,用引号括起来
的组名称则只能用例子中给的值。
02b50b05283e98dd0fd71db496ef01e8,kubelet-bootstrap,10001,"system:bootstrappers"
向 kube-apiserver 添加 --token-auth-file=FILENAME 标志(或许这要对 systemd
的单元文件作修改)以启用令牌文件。参见
这里
的文档以了解进一步的细节。
授权 kubelet 创建 CSR 现在启动引导节点被身份认证为 system:bootstrapping 组的成员,它需要被 授权
创建证书签名请求(CSR)并在证书被签名之后将其取回。
幸运的是,Kubernetes 提供了一个 ClusterRole,其中精确地封装了这些许可,
system:node-bootstrapper。
为了实现这一点,你只需要创建 ClusterRoleBinding,将 system:bootstrappers
组绑定到集群角色 system:node-bootstrapper。
# 允许启动引导节点创建 CSR
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: create-csrs-for-bootstrapping
subjects:
- kind: Group
name: system:bootstrappers
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: system:node-bootstrapper
apiGroup: rbac.authorization.k8s.io
kube-controller-manager 配置 API 服务器从 kubelet 收到证书请求并对这些请求执行身份认证,但真正负责发放
签名证书的是控制器管理器。
控制器管理器通过一个证书发放的控制回路来执行此操作。该操作的执行方式是使用磁盘上
的文件用 cfssl 本地签名组件
来完成。目前,所发放的所有证书都有一年的有效期,并设定了默认的一组密钥用法。
为了让控制器管理器对证书签名,它需要:
能够访问你之前所创建并分发的“Kubernetes CA 密钥和证书” 启用 CSR 签名 访问密钥和证书 如前所述,你需要创建一个 Kubernetes CA 密钥和证书,并将其发布到主控节点。
这些数据会被控制器管理器来对 kubelet 证书进行签名。
由于这些被签名的证书反过来会被 kubelet 用来在 kube-apiserver 执行普通的
kubelet 身份认证,很重要的一点是为控制器管理器所提供的 CA 也被 kube-apiserver
信任用来执行身份认证。CA 密钥和证书是通过 kube-apiserver 的标志
--client-ca-file=FILENAME(例如,--client-ca-file=/var/lib/kubernetes/ca.pem),
来设定的,正如 kube-apiserver 配置节所述。
要将 Kubernetes CA 密钥和证书提供给 kube-controller-manager,可使用以下标志:
--cluster-signing-cert-file="/etc/path/to/kubernetes/ca/ca.crt" --cluster-signing-key-file="/etc/path/to/kubernetes/ca/ca.key"
例如:
--cluster-signing-cert-file="/var/lib/kubernetes/ca.pem" --cluster-signing-key-file="/var/lib/kubernetes/ca-key.pem"
所签名的证书的合法期限可以通过下面的标志来配置:
--cluster-signing-duration
批复 为了对 CSR 进行批复,你需要告诉控制器管理器批复这些 CSR 是可接受的。
这是通过将 RBAC 访问权限授予正确的组来实现的。
许可权限有两组:
nodeclient:如果节点在为节点创建新的证书,则该节点还没有证书。该节点
使用前文所列的令牌之一来执行身份认证,因此是组 system:bootstrappers 组
的成员。selfnodeclient:如果节点在对证书执行续期操作,则该节点已经拥有一个证书。
节点持续使用现有的证书将自己认证为 system:nodes 组的成员。要允许 kubelet 请求并接收新的证书,可以创建一个 ClusterRoleBinding 将启动
引导节点所处的组 system:bootstrappers 绑定到为其赋予访问权限的
ClusterRole system:certificates.k8s.io:certificatesigningrequests:nodeclient:
# 批复 "system:bootstrappers" 组的所有 CSR
apiVersion : rbac.authorization.k8s.io/v1
kind : ClusterRoleBinding
metadata :
name : auto-approve-csrs-for-group
subjects :
- kind : Group
name : system:bootstrappers
apiGroup : rbac.authorization.k8s.io
roleRef :
kind : ClusterRole
name : system:certificates.k8s.io:certificatesigningrequests:nodeclient
apiGroup : rbac.authorization.k8s.io
要允许 kubelet 对其客户端证书执行续期操作,可以创建一个 ClusterRoleBinding
将正常工作的节点所处的组 system:nodes 绑定到为其授予访问许可的 ClusterRole
system:certificates.k8s.io:certificatesigningrequests:selfnodeclient:
# 批复 "system:nodes" 组的 CSR 续约请求
apiVersion : rbac.authorization.k8s.io/v1
kind : ClusterRoleBinding
metadata :
name : auto-approve-renewals-for-nodes
subjects :
- kind : Group
name : system:nodes
apiGroup : rbac.authorization.k8s.io
roleRef :
kind : ClusterRole
name : system:certificates.k8s.io:certificatesigningrequests:selfnodeclient
apiGroup : rbac.authorization.k8s.io
作为 kube-controller-manager
的一部分的 csrapproving 控制器是自动被启用的。
该控制器使用 SubjectAccessReview API
来确定是否某给定用户被授权请求 CSR,之后基于鉴权结果执行批复操作。
为了避免与其它批复组件发生冲突,内置的批复组件不会显式地拒绝任何 CSRs。
该组件仅是忽略未被授权的请求。
控制器也会作为垃圾收集的一部分清除已过期的证书。
kubelet 配置 最后,当主控节点被正确配置并且所有必要的身份认证和鉴权机制都就绪时,
我们可以配置 kubelet。
kubelet 需要以下配置来执行启动引导:
一个用来存储所生成的密钥和证书的路径(可选,可以使用默认配置) 一个用来指向尚不存在的 kubeconfig 文件的路径;kubelet 会将启动引导
配置文件放到这个位置 一个指向启动引导 kubeconfig 文件的路径,用来提供 API 服务器的 URL
和启动引导凭据,例如,启动引导令牌 可选的:轮换证书的指令 启动引导 kubeconfig 文件应该放在一个 kubelet 可访问的路径下,例如
/var/lib/kubelet/bootstrap-kubeconfig。
其格式与普通的 kubeconfig 文件完全相同。实例文件可能看起来像这样:
apiVersion : v1
kind : Config
clusters :
- cluster :
certificate-authority : /var/lib/kubernetes/ca.pem
server : https://my.server.example.com:6443
name : bootstrap
contexts :
- context :
cluster : bootstrap
user : kubelet-bootstrap
name : bootstrap
current-context : bootstrap
preferences : {}
users :
- name : kubelet-bootstrap
user :
token : 07401b.f395accd246ae52d
需要额外注意的一些因素有:
certificate-authority:指向 CA 文件的路径,用来对 kube-apiserver 所出示
的服务器证书进行验证server: 用来访问 kube-apiserver 的 URLtoken:要使用的令牌令牌的格式并不重要,只要它与 kube-apiserver 的期望匹配即可。
在上面的例子中,我们使用的是启动引导令牌。
如前所述,任何合法的身份认证方法都可以使用,不限于令牌。
因为启动引导 kubeconfig 文件是一个标准的 kubeconfig 文件,你可以使用
kubectl 来生成该文件。要生成上面的示例文件:
kubectl config --kubeconfig=/var/lib/kubelet/bootstrap-kubeconfig set-cluster bootstrap --server='https://my.server.example.com:6443' --certificate-authority=/var/lib/kubernetes/ca.pem
kubectl config --kubeconfig=/var/lib/kubelet/bootstrap-kubeconfig set-credentials kubelet-bootstrap --token=07401b.f395accd246ae52d
kubectl config --kubeconfig=/var/lib/kubelet/bootstrap-kubeconfig set-context bootstrap --user=kubelet-bootstrap --cluster=bootstrap
kubectl config --kubeconfig=/var/lib/kubelet/bootstrap-kubeconfig use-context bootstrap
要指示 kubelet 使用启动引导 kubeconfig 文件,可以使用下面的 kubelet 标志:
--bootstrap-kubeconfig="/var/lib/kubelet/bootstrap-kubeconfig" --kubeconfig="/var/lib/kubelet/kubeconfig"
在启动 kubelet 时,如果 --kubeconfig 标志所指定的文件并不存在,会使用通过标志
--bootstrap-kubeconfig 所指定的启动引导 kubeconfig 配置来向 API 服务器请求
客户端证书。在证书请求被批复并被 kubelet 收回时,一个引用所生成的密钥和所获得
证书的 kubeconfig 文件会被写入到通过 --kubeconfig 所指定的文件路径下。
证书和密钥文件会被放到 --cert-dir 所指定的目录中。
客户和服务证书 前文所述的内容都与 kubelet 客户端 证书相关,尤其是 kubelet 用来向
kube-apiserver 认证自身身份的证书。
kubelet 也可以使用 服务(Serving) 证书。kubelet 自身向外提供一个
HTTPS 末端,包含若干功能特性。要保证这些末端的安全性,kubelet 可以执行以下操作
之一:
使用通过 --tls-private-key-file 和 --tls-cert-file 所设置的密钥和证书 如果没有提供密钥和证书,则创建自签名的密钥和证书 通过 CSR API 从集群服务器请求服务证书 TLS 启动引导所提供的客户端证书默认被签名为仅用于 client auth(客户端认证),
因此不能作为提供服务的证书,或者 server auth。
不过,你可以启用服务器证书,至少可以部分地通过证书轮换来实现这点。
证书轮换 Kubernetes v1.8 和更高版本的 kubelet 实现了对客户端证书与/或服务证书进行轮换
这一 Beta 特性。这一特性通过 kubelet 对应的 RotateKubeletClientCertificate 和
RotateKubeletServerCertificate 特性门控标志来控制,并且是默认启用的。
RotateKubeletClientCertificate 会导致 kubelet 在其现有凭据即将过期时通过
创建新的 CSR 来轮换其客户端证书。要启用此功能特性,可将下面的标志传递给
kubelet:
--rotate-certificates
RotateKubeletServerCertificate 会让 kubelet 在启动引导其客户端凭据之后请求
一个服务证书 且 对该服务证书执行轮换操作。要启用此功能特性,将下面的标志
传递给 kubelet:
--rotate-server-certificates
说明: Kubernetes 核心中所实现的 CSR 批复控制器出于
安全原因
并不会自动批复节点的 服务 证书。
要使用 RotateKubeletServerCertificate 功能特性,集群运维人员需要运行一个
定制的控制器或者手动批复服务证书的请求。
对 kubelet 服务证书的批复过程因集群部署而异,通常应该仅批复如下 CSR:
由节点发出的请求(确保 spec.username 字段形式为 system:node:<nodeName>
且 spec.groups 包含 system:nodes) 请求中包含服务证书用法(确保 spec.usages 中包含 server auth,可选地也可
包含 digital signature 和 key encipherment,且不包含其它用法) 仅包含隶属于请求节点的 IP 和 DNS 的 subjectAltNames,没有 URI 和 Email
形式的 subjectAltNames(解析 spec.request 中的 x509 证书签名请求可以
检查 subjectAltNames) 其它身份认证组件 本文所描述的所有 TLS 启动引导内容都与 kubelet 相关。不过,其它组件也可能需要
直接与 kube-apiserver 直接通信。容易想到的是 kube-proxy,同样隶属于
Kubernetes 的控制面并且运行在所有节点之上,不过也可能包含一些其它负责
监控或者联网的组件。
与 kubelet 类似,这些其它组件也需要一种向 kube-apiserver 认证身份的方法。
你可以用几种方法来生成这类凭据:
较老的方式:和 kubelet 在 TLS 启动引导之前所做的一样,用类似的方式
创建和分发证书 DaemonSet:由于 kubelet 自身被加载到所有节点之上,并且有足够能力来启动基本服务,
你可以运行将 kube-proxy 和其它特定节点的服务作为 kube-system 名字空间中的
DaemonSet 来执行,而不是独立的进程。由于 DaemonSet 位于集群内部,你可以为其
指派一个合适的服务账户,使之具有适当的访问权限来完成其使命。这也许是配置此类
服务的最简单的方法。 kubectl 批复 CSRs 可以在控制器管理其内置的批复工作流之外被批复。
签名控制器并不会立即对所有证书请求执行签名操作。相反,它会等待这些请求被某
具有适当特权的用户标记为 “Approved(已批准)”状态。
这一流程有意允许由外部批复控制器来自动执行的批复,或者由控制器管理器内置的
批复控制器来自动批复。
不过,集群管理员也可以使用 kubectl 来手动批准证书请求。
管理员可以通过 kubectl get csr 来列举所有的 CSR,使用
kubectl descsribe csr <name> 来描述某个 CSR 的细节。
管理员可以使用 kubectl certificate approve <name 来批准某 CSR,或者
kubectl certificate deny <name> 来拒绝某 CSR。
6.10 - 调度 6.10.1 - 调度策略 kube-scheduler
根据调度策略指定的断言(predicates)和 优先级(priorities)
分别对节点进行过滤和打分 。
你可以通过执行 kube-scheduler --policy-config-file <filename> 或
kube-scheduler --policy-configmap <ConfigMap>
设置并使用调度策略 。
断言 以下断言 实现了过滤接口:
PodFitsHostPorts:检查 Pod 请求的端口(网络协议类型)在节点上是否可用。PodFitsHost:检查 Pod 是否通过主机名指定了 Node。PodFitsResources:检查节点的空闲资源(例如,CPU和内存)是否满足 Pod 的要求。MatchNodeSelector:检查 Pod 的节点选择算符
和节点的 标签 是否匹配。NoVolumeZoneConflict:给定该存储的故障区域限制,
评估 Pod 请求的卷 在节点上是否可用。NoDiskConflict:根据 Pod 请求的卷是否在节点上已经挂载,评估 Pod 和节点是否匹配。MaxCSIVolumeCount:决定附加 CSI 卷的数量,判断是否超过配置的限制。CheckNodeMemoryPressure:如果节点正上报内存压力,并且没有异常配置,则不会把 Pod 调度到此节点上。CheckNodePIDPressure:如果节点正上报进程 ID 稀缺,并且没有异常配置,则不会把 Pod 调度到此节点上。CheckNodeDiskPressure:如果节点正上报存储压力(文件系统已满或几乎已满),并且没有异常配置,则不会把 Pod 调度到此节点上。CheckNodeCondition:节点可用上报自己的文件系统已满,网络不可用或者 kubelet 尚未准备好运行 Pod。
如果节点上设置了这样的状况,并且没有异常配置,则不会把 Pod 调度到此节点上。PodToleratesNodeTaints:检查 Pod 的容忍
是否能容忍节点的污点 。CheckVolumeBinding:基于 Pod 的卷请求,评估 Pod 是否适合节点,这里的卷包括绑定的和未绑定的
PVCs 都适用。优先级 以下优先级 实现了打分接口:
LeastRequestedPriority:偏向最少请求资源的节点。
换句话说,节点上的 Pod 越多,使用的资源就越多,此策略给出的排名就越低。MostRequestedPriority:支持最多请求资源的节点。
该策略将 Pod 调度到整体工作负载所需的最少的一组节点上。RequestedToCapacityRatioPriority:使用默认的打分方法模型,创建基于 ResourceAllocationPriority 的 requestedToCapacity。BalancedResourceAllocation:偏向平衡资源使用的节点。NodePreferAvoidPodsPriority:根据节点的注解 scheduler.alpha.kubernetes.io/preferAvoidPods 对节点进行优先级排序。
你可以使用它来暗示两个不同的 Pod 不应在同一节点上运行。NodeAffinityPriority:根据节点亲和中 PreferredDuringSchedulingIgnoredDuringExecution 字段对节点进行优先级排序。
你可以在将 Pod 分配给节点 中了解更多。TaintTolerationPriority:根据节点上无法忍受的污点数量,给所有节点进行优先级排序。
此策略会根据排序结果调整节点的等级。ImageLocalityPriority:偏向已在本地缓存 Pod 所需容器镜像的节点。ServiceSpreadingPriority:对于给定的 Service,此策略旨在确保该 Service 关联的 Pod 在不同的节点上运行。
它偏向把 Pod 调度到没有该服务的节点。
整体来看,Service 对于单个节点故障变得更具弹性。EqualPriority:给予所有节点相等的权重。接下来 6.10.2 - 调度器配置 FEATURE STATE: Kubernetes v1.19 [beta]
你可以通过编写配置文件,并将其路径传给 kube-scheduler 的命令行参数,定制 kube-scheduler 的行为。
调度模板(Profile)允许你配置 kube-scheduler
中的不同调度阶段。每个阶段都暴露于某个扩展点中。插件通过实现一个或多个扩展点来提供调度行为。
你可以通过运行 kube-scheduler --config <filename> 来设置调度模板,
配置文件使用组件配置的 API (v1alpha1 )。
最简单的配置如下:
apiVersion : kubescheduler.config.k8s.io/v1beta1
kind : KubeSchedulerConfiguration
clientConnection :
kubeconfig : /etc/srv/kubernetes/kube-scheduler/kubeconfig
配置文件 通过调度配置文件,你可以配置 kube-scheduler 在不同阶段的调度行为。
每个阶段都在一个扩展点 中公开。
调度插件 通过实现一个或多个扩展点,来提供调度行为。
你可以配置同一 kube-scheduler 实例使用多个配置文件 。
扩展点 调度行为发生在一系列阶段中,这些阶段是通过以下扩展点公开的:
QueueSort:这些插件对调度队列中的悬决的 Pod 排序。
一次只能启用一个队列排序插件。PreFilter:这些插件用于在过滤之前预处理或检查 Pod 或集群的信息。
它们可以将 Pod 标记为不可调度。Filter:这些插件相当于调度策略中的断言(Predicates),用于过滤不能运行 Pod 的节点。
过滤器的调用顺序是可配置的。
如果没有一个节点通过所有过滤器的筛选,Pod 将会被标记为不可调度。PreScore:这是一个信息扩展点,可用于预打分工作。Score:这些插件给通过筛选阶段的节点打分。调度器会选择得分最高的节点。Reserve:这是一个信息扩展点,当资源已经预留给 Pod 时,会通知插件。
这些插件还实现了 Unreserve 接口,在 Reserve 期间或之后出现故障时调用。Permit:这些插件可以阻止或延迟 Pod 绑定。PreBind:这些插件在 Pod 绑定节点之前执行。Bind:这个插件将 Pod 与节点绑定。绑定插件是按顺序调用的,只要有一个插件完成了绑定,其余插件都会跳过。绑定插件至少需要一个。PostBind:这是一个信息扩展点,在 Pod 绑定了节点之后调用。对每个扩展点,你可以禁用默认插件 或者是启用自己的插件,例如:
apiVersion : kubescheduler.config.k8s.io/v1beta1
kind : KubeSchedulerConfiguration
profiles :
- plugins :
score :
disabled :
- name : NodeResourcesLeastAllocated
enabled :
- name : MyCustomPluginA
weight : 2
- name : MyCustomPluginB
weight : 1
你可以在 disabled 数组中使用 * 禁用该扩展点的所有默认插件。
如果需要,这个字段也可以用来对插件重新顺序。
调度插件 UnReserve:这是一个信息扩展点,如果一个 Pod 在预留后被拒绝,并且被 Permit 插件搁置,它就会被调用。调度插件 下面默认启用的插件实现了一个或多个扩展点:
DefaultBinder:提供默认的绑定机制。
实现的扩展点:Bind。
你也可以通过组件配置 API 启用以下插件(默认不启用):
多配置文件 你可以配置 kube-scheduler 运行多个配置文件。
每个配置文件都有一个关联的调度器名称,并且可以在其扩展点中配置一组不同的插件。
使用下面的配置样例,调度器将运行两个配置文件:一个使用默认插件,另一个禁用所有打分插件。
apiVersion : kubescheduler.config.k8s.io/v1beta1
kind : KubeSchedulerConfiguration
profiles :
- schedulerName : default-scheduler
- schedulerName : no -scoring-scheduler
plugins :
preScore :
disabled :
- name : '*'
score :
disabled :
- name : '*'
对于那些希望根据特定配置文件来进行调度的 Pod,可以在 .spec.schedulerName 字段指定相应的调度器名称。
默认情况下,将创建一个调度器名为 default-scheduler 的配置文件。
这个配置文件包括上面描述的所有默认插件。
声明多个配置文件时,每个配置文件中调度器名称必须唯一。
如果 Pod 未指定调度器名称,kube-apiserver 将会把调度器名设置为 default-scheduler。
因此,应该存在一个调度器名为 default-scheduler 的配置文件来调度这些 Pod。
说明: Pod 的调度事件把 .spec.schedulerName 字段值作为 ReportingController。
领导者选举事件使用列表中第一个配置文件的调度器名称。
说明: 所有配置文件必须在 QueueSort 扩展点使用相同的插件,并具有相同的配置参数(如果适用)。
这是因为调度器只有一个保存 pending 状态 Pod 的队列。
接下来 6.11 - 工具 Kubernetes 包含一些内置工具,可以帮助用户更好的使用 Kubernetes 系统。
Kubectl kubectl 是 Kubernetes 命令行工具,
可以用来操控 Kubernetes 集群。
Kubeadm kubeadm 是一个命令行工具,
可以用来在物理机、云服务器或虚拟机(目前处于 alpha 阶段)
上轻松部署一个安全可靠的 Kubernetes 集群。
Minikube minikube 是一个可以方便用户
在其工作站点本地部署一个单节点 Kubernetes 集群的工具,用于开发和测试。
Dashboard Dashboard
是 Kubernetes 基于 Web 的用户管理界面,允许用户部署容器化应用到 Kubernetes
集群,进行故障排查以及管理集群和集群资源。
Helm Kubernetes Helm 是一个管理
预先配置完毕的 Kubernetes 资源包的工具,这里的资源在 Helm 中也被称作
Kubernetes charts。
使用 Helm:
查找并使用已经打包为 Kubernetes charts 的流行软件 分享您自己的应用作为 Kubernetes charts 为 Kubernetes 应用创建可重复执行的构建 为您的 Kubernetes 清单文件提供更智能化的管理 管理 Helm 软件包的发布 Kompose Kompose 一个转换工具,
用来帮助 Docker Compose 用户迁移至 Kubernetes。
使用 Kompose:
将一个 Docker Compose 文件解释成 Kubernetes 对象 将本地 Docker 开发 转变成通过 Kubernetes 来管理 转换 v1 或 v2 Docker Compose yaml 文件 或
已发布的应用程序包 7 - 为 Kubernetes 文档出一份力 Kubernetes 欢迎来自所有贡献者的改进,无论你是新人和有经验的贡献者!
说明: 要了解有关为 Kubernetes 做出贡献的更多信息,请参阅
贡献者文档 .
本网站由 Kubernetes SIG(特别兴趣小组) Docs 维护。
Kubernetes 文档项目的贡献者:
改进现有内容 创建新内容 翻译文档 管理并发布 Kubernetes 周期性发行版的文档 Kubernetes 文档欢迎来自各方贡献者的改进,无论新手还是高手!
入门 任何人都可以提出文档方面的问题(issue),或贡献一个变更,用拉取请求(PR)的方式提交到
GitHub 上的 kubernetes/website 仓库 。
当然你需要熟练使用 git 和 GitHub 才能在 Kubernetes 社区中有效工作。
如何参与文档编制:
签署 CNCF 的贡献者许可协议 。 熟悉文档仓库
和网站的静态站点生成器 。 确保理解
发起 PR 和
审查变更 的基本流程。 有些任务要求 Kubernetes 组织内更高的信任级别和访问权限。
阅读参与 SIG Docs 工作 ,获取角色和权限的更多细节。
第一次贡献 下一步 参与 SIG Docs 工作 SIG Docs 是负责发布、维护 Kubernetes 文档的贡献者团体。
参与 SIG Docs 是 Kubernetes 贡献者(开发者和其他人员)对 Kubernetes 项目产生重大影响力的好方式。
SIG Docs 的几种沟通方式:
其他贡献方式 7.1 - 提出内容改进建议 如果你发现 Kubernetes 文档中存在问题,或者你有一个关于新内容的想法,可以考虑
提出一个问题(issue)。你只需要具有 GitHub 账号 和 Web
浏览器就可以完成这件事。
在大多数情况下,Kubernetes 文档的新工作都是开始于 GitHub 上的某个问题。
Kubernetes 贡献者会审阅这些问题并根据需要对其分类、打标签。
接下来,你或者别的 Kubernetes 社区成员就可以发起一个带有变更的拉取请求,
以解决这一问题。
创建问题 如果你希望就改进已有内容提出建议,或者在文档中发现了错误,请创建一个问题(issue)。
滚动到页面底部,点击“报告问题”按钮。浏览器会重定向到一个 GitHub 问题页面,其中
包含了一些预先填充的内容。 请描述遇到的问题或关于改进的建议。尽可能提供细节信息。 点击 提交新问题 . 提交之后,偶尔查看一下你所提交的问题,或者开启 GitHub 通知。
评审人(reviewers)和其他社区成员可能在针对所提问题采取行动之前,问一些问题。
关于新内容的建议 如果你对新内容有想法,但是你有不确定这些内容应该放在哪里,你仍可以提出问题。
如何更好地记录问题 在记录问题时,请注意以下事项:
提供问题的清晰描述,描述具体缺失的内容、过期的内容、错误的内容或者需要改进的文字。 解释该问题对用户的特定影响。 将给定问题的范围限定在一个工作单位范围内。如果问题牵涉的领域较大,可以将其分解为多个
小一点的问题。例如:"Fix the security docs" 是一个过于宽泛的问题,而
"Add details to the 'Restricting network access' topic"
就是一个足够具体的、可操作的问题。 搜索现有问题的列表,查看是否已经有相关的或者类似的问题已被记录。 如果新问题与某其他问题或 PR 有关联,可以使用其完整 URL 或带 # 字符的 PR 编号
来引用之。例如:Introduced by #987654。 遵从行为准则 。尊重同行贡献者。
例如,"The docs are terrible" 就是无用且无礼的反馈。
7.2 - 贡献新内容 7.2.1 - 贡献新内容概述 本节包含贡献新内容之前你需要知晓的一些信息。
基本知识 使用 Markdown 来编写 Kubernetes 文档并使用 Hugo 来构建网站 源代码位于 GitHub 仓库中。
你可以在 /content/en/docs/ 目录下找到 Kubernetes 文档。
某些参考文档是使用位于 update-imported-docs/ 目录下的脚本自动生成的。 页面内容类型 使用 Hugo 描述文档内容的表现。除了基本的 Hugo 短代码(shortcodes)外,我们还在文档中使用一些
定制的 Hugo 短代码 以控制内容的表现。 文档的源代码有多种语言形式,位于/content/ 目录下。
每种语言都有自己的由两个字母代表的目录,这两个字母是基于
ISO 639-1 标准 来确定的。
例如,英语文档源码位于/content/en/docs/ 目录下。 关于在多种语言中为文档做贡献的详细信息,以及如何启动一种新的语言翻译,
可参考本地化 文档。 开始之前 签署 CNCF CLA 所有 Kubernetes 贡献者 必须 阅读
贡献者指南
并签署贡献者授权同意书(Contributor License Agreement,CLA) 。
来自尚未签署 CLA 的贡献者的 PR 无法通过自动化服务的测试。
你所提供的姓名和邮件地址必须与 git config 中所找到的完全相同,
而且你的 git 用户名和邮件地址必须与用来签署 CNCF CLA 的一致。
选择要使用的分支 在发起拉取请求时,你需要预先知道要基于哪个分支来开展工作。
场景 分支 针对当前发行版本的,对现有英文内容的修改或新的英文内容 master针对功能特性变更的内容 功能特性所对应的版本所对应的分支,分支名字模式为 dev-<version>。例如,如果某功能特性在 v1.25 版本发生变化,则对应的文档变化要添加到 dev-1.25 分支。 其他语言的内容(本地化) 基于本地化团队的约定。参见本地化分支策略 了解更多信息。
如果你仍不能确定要选择哪个分支,请在 #sig-docs Slack 频道上提问。
说明: 如果你已经提交了你的 PR,并且你发现所针对的分支选错了,你(且只能是你)可以重新选择分支。
每个 PR 牵涉的语言 请限制每个 PR 仅涉及一种语言。
如果你需要对多种语言下的同一代码示例进行相同的修改,也请为每种语言发起一个独立的 PR。
为贡献者提供的工具 kubernetes/website 仓库的
文档贡献者工具
目录中包含了一些工具,能够助你的贡献过程更为顺畅。
7.2.2 - 发起拉取请求(PR) 说明: 代码开发者们 :如果你在为下一个 Kubernetes 发行版本中的某功能特性
撰写文档,请参考
为新功能撰写文档 。
要贡献新的内容页面或者改进已有内容页面,请发起拉取请求(PR)。
请确保你满足了开始之前
节中所列举的所有要求。
如果你所提交的变更足够小,或者你对 git 工具不熟悉,可以阅读
使用 GitHub 提交变更 以了解如何编辑页面。
如果所提交的变更较大,请阅读基于本地克隆副本开展工作 以学习
如何在你本地计算机上构造变更。
使用 GitHub 提交变更 如果你在 git 工作流方面欠缺经验,这里有一种发起拉取请求的更为简单的方法。
在你发现问题的网页,选择右上角的铅笔图标。你也可以滚动到页面底端,选择
编辑此页面 。
在 GitHub 的 Markdown 编辑器中修改内容。
在编辑器的下方,填写 建议文件变更 表单。
在第一个字段中,为你的提交消息取一个标题。
在第二个字段中,为你的提交写一些描述文字。
选择 Propose File Change .
选择 Create pull request .
在 Open a pull request 屏幕上填写表单:
Subject 字段默认为提交的概要信息。你可以根据需要修改它。Body 字段包含更为详细的提交消息,如果你之前有填写过的话,以及一些模板文字。
填写模板所要求的详细信息,之后删除多余的模板文字。确保 Allow edits from maintainers 复选框被勾选。 说明: PR 描述信息是帮助 PR 评阅人了解你所提议的变更的重要途径。
更多信息请参考
发起一个 PR .
选择 Create pull request . 在 GitHub 上处理反馈意见 在合并 PR 之前,Kubernetes 社区成员会评阅并批准它。
k8s-ci-robot 会基于页面中最近提及的属主来建议评阅人(reviewers)。
如果你希望特定某人来评阅,可以留下评论,提及该用户的 GitHub 用户名。
如果某个评阅人请你修改 PR:
前往 Files changed Tab 页面; 选择 PR 所修改的任何文件所对应的铅笔(edit)图标; 根据建议作出修改; 提交所作修改。 如果你希望等待评阅人的反馈,可以每 7 天左右联系一次。
你也可以在 #sig-docs Slack 频道发送消息。
当评阅过程结束,某个评阅人会合并你的 PR。
几分钟之后,你所做的变更就会上线了。
基于本地克隆副本开展工作 如果你有 git 的使用经验,或者你要提议的修改不仅仅几行,请使用本地克隆副本
来开展工作。
首先要确保你在本地计算机上安装了 git 。
你也可以使用 git 的带用户界面的应用。
派生 kubernetes/website 仓库 前往 kubernetes/website 仓库; 选择 Fork . 创建一个本地克隆副本并指定 upstream 仓库 打开终端窗口,克隆你所派生的副本:
git clone git@github.com/<github_username>/website
前往新的 website 目录,将 kubernetes/website 仓库设置为 upstream
远端:
cd website
git remote add upstream https://github.com/kubernetes/website.git
确认你现在有两个仓库,origin 和 upstream:
输出类似于:
origin git@github.com:<github_username>/website.git ( fetch)
origin git@github.com:<github_username>/website.git ( push)
upstream https://github.com/kubernetes/website ( fetch)
upstream https://github.com/kubernetes/website ( push)
从你的克隆副本取回 origin/master 分支,从 kubernetes/website 取回 upstream/master:
git fetch origin
git fetch upstream
这样可以确保你本地的仓库在开始工作前是最新的。
创建一个分支 决定你要基于哪个分支来开展工作:
针对已有内容的改进,请使用 upstream/master; 针对已有功能特性的新文档内容,请使用 upstream/master; 对于本地化内容,请基于本地化的约定。
可参考对 Kubernetes 文档进行本地化 了解详细信息。 对于在下一个 Kubernetes 版本中新功能特性的文档,使用独立的功能特性分支。
参考为发行版本功能特性撰写文档 了解更多信息。 对于很多 SIG Docs 共同参与的,需较长时间才完成的任务,例如内容的重构,
请使用为该任务创建的特性分支。 如果你在选择分支上需要帮助,请在 #sig-docs Slack 频道提问。
基于第一步中选定的分支,创建新分支。
下面的例子假定基础分支是 upstream/master:
git checkout -b <my_new_branch> upstream/master
使用文本编辑器开始构造变更。 在任何时候,都可以使用 git status 命令查看你所改变了的文件列表。
提交你的变更 当你准备好发起拉取请求(PR)时,提交你所做的变更。
在你的本地仓库中,检查你要提交的文件:
输出类似于:
On branch <my_new_branch>
Your branch is up to date with 'origin/<my_new_branch>' .
Changes not staged for commit:
( use "git add <file>..." to update what will be committed)
( use "git checkout -- <file>..." to discard changes in working directory)
modified: content/en/docs/contribute/new-content/contributing-content.md
no changes added to commit ( use "git add" and/or "git commit -a" )
将 Changes not staged for commit 下列举的文件添加到提交中:
针对每个文件重复此操作。
添加完所有文件之后,创建一个提交(commit):
git commit -m "Your commit message"
说明: 不要在提交消息中使用任何
GitHub 关键字 。
你可以在后面创建 PR 时使用这些关键字。
推送你本地分支及其中的新提交到你的远程派生副本库:
git push origin <my_new_branch>
在本地预览你的变更 在推送变更或者发起 PR 之前在本地查看一下预览是个不错的注意。
通过预览你可以发现构建错误或者 Markdown 格式问题。
你可以构造网站的容器镜像或者在本地运行 Hugo。
构造容器镜像的方式比较慢,不过能够显示 Hugo 短代码(shortcodes) ,
因此对于调试是很有用的。
说明: 下面的命令中使用 Docker 作为默认的容器引擎。
如果需要重载这一行为,可以设置 CONTAINER_ENGINE。
在本地构造镜像;
# 使用 docker (默认)
make container-image
### 或 ###
# 使用 podman
CONTAINER_ENGINE = podman make container-image
在本地构造了 kubernetes-hugo 镜像之后,可以构造并启动网站:
# 使用 docker (默认)
make container-serve
### 或 ###
# 使用 podman
CONTAINER_ENGINE = podman make container-serve
启动浏览器,浏览 https://localhost:1313。
Hugo 会监测文件的变更并根据需要重新构建网站。
要停止本地 Hugo 实例,可返回到终端并输入 Ctrl+C,或者关闭终端窗口。
另一种方式是,在你的本地计算机上安装并使用 hugo 命令:
安装 website/netlify.toml
文件中指定的 Hugo 版本。
启动一个终端窗口,进入 Kubernetes 网站仓库目录,启动 Hugo 服务器:
cd <path_to_your_repo>/website
hugo server
在浏览器的地址栏输入: https://localhost:1313。 要停止本地 Hugo 实例,返回到终端窗口并输入 Ctrl+C 或者关闭终端窗口。 从你的克隆副本向 kubernetes/website 发起拉取请求(PR) 在 Web 浏览器中,前往 kubernetes/website 仓库;
点击 New Pull Request ;
选择 compare across forks ;
从 head repository 下拉菜单中,选取你的派生仓库;
从 compare 下拉菜单中,选择你的分支;
点击 Create Pull Request ;
为你的拉取请求添加一个描述:
Title (不超过 50 个字符):总结变更的目的;Description :给出变更的详细信息;如果存在一个相关联的 GitHub Issue,可以在描述中包含 Fixes #12345 或
Closes #12345。GitHub 的自动化设施能够在当前 PR 被合并时自动关闭所提及
的 Issue。如果有其他相关联的 PR,也可以添加对它们的链接。 如果你尤其希望获得某方面的建议,可以在描述中包含你希望评阅人思考的问题。 点击 Create pull request 按钮。
祝贺你! 你的拉取请求现在出现在 Pull Requests 列表中了!
在发起 PR 之后,GitHub 会执行一些自动化的测试,并尝试使用
Netlify 部署一个预览版本。
如果 Netlify 构建操作失败,可选择 Details 了解详细信息。 如果 Netlify 构建操作成功,选择 Details 会打开 Kubernetes 的一个预览
版本,其中包含了你所作的变更。评阅人也使用这一功能来检查你的变更。 GitHub 也会自动为 PR 分派一些标签,以帮助评阅人。
如果有需要,你也可以向 PR 添加标签。
欲了解相关详细信息,可以参考
添加和删除 Issue 标签 。
在本地处理反馈 在本地完成修改之后,可以修补(amend)你之前的提交:
-a:提交所有修改--amend:对前一次提交进行增补,而不是创建新的提交如果有必要,更新你的提交消息;
使用 git push origin <my_new_branch> 来推送你的变更,重新出发 Netlify 测试。
说明: 如果你使用
git commit -m 而不是增补参数,在 PR 最终合并之前你必须
squash 你的提交 。
来自评阅人的修改 有时评阅人会向你的 PR 中提交修改。在作出其他修改之前,请先取回这些提交。
从你的远程派生副本仓库取回提交,让你的工作分支基于所取回的分支:
git fetch origin
git rebase origin/<your-branch-name>
变更基线(rebase)操作完成之后,强制推送本地的新改动到你的派生仓库:
git push --force-with-lease origin <your-branch-name>
合并冲突和重设基线 如果另一个贡献者在别的 PR 中提交了对同一文件的修改,这可能会造成合并冲突。
你必须在你的 PR 中解决所有合并冲突。
更新你的派生副本,重设本地分支的基线:
git fetch origin
git rebase origin/<your-branch-name>
之后强制推送修改到你的派生副本仓库:
git push --force-with-lease origin <your-branch-name>
从 kubernetes/website 的 upstream/master 分支取回更改,然后重设本地分支的基线:
git fetch upstream
git rebase upstream/master
检查重设基线操作之后的状态:
你会看到一组存在冲突的文件。
打开每个存在冲突的文件,查找冲突标记:>>>、<<< 和 ===。
解决完冲突之后删除冲突标记。
添加文件到变更集合:
继续执行基线变更(rebase)操作:
根据需要重复步骤 2 到 5。
在应用完所有提交之后,git status 命令会显示 rebase 操作完成。
将分支强制推送到你的派生仓库:
git push --force-with-lease origin <your-branch-name>
PR 不再显示存在冲突。
压缩(Squashing)提交 如果你的 PR 包含多个提交(commits),你必须将其压缩成一个提交才能被合并。
你可以在 PR 的 Commits Tab 页面查看提交个数,也可以在本地通过
git log 命令查看提交个数。
说明: 本主题假定使用 vim 作为命令行文本编辑器。
启动一个交互式的 rebase 操作:
git rebase -i HEAD~<number_of_commits_in_branch>
压缩提交的过程也是一种重设基线的过程。
这里的 -i 开关告诉 git 你希望交互式地执行重设基线操作。
HEAD~<number_of_commits_in_branch 表明在 rebase 操作中查看多少个提交。
输出类似于;
pick d875112ca Original commit
pick 4fa167b80 Address feedback 1
pick 7d54e15ee Address feedback 2
# Rebase 3d18sf680..7d54e15ee onto 3d183f680 (3 commands)
...
# These lines can be re-ordered; they are executed from top to bottom.
输出的第一部分列举了重设基线操作中的提交。
第二部分给出每个提交的选项。
改变单词 pick 就可以改变重设基线操作之后提交的状态。
就重设基线操作本身,我们关注 squash 和 pick 选项。
开始编辑文件。
修改原来的文本:
pick d875112ca Original commit
pick 4fa167b80 Address feedback 1
pick 7d54e15ee Address feedback 2
使之成为:
pick d875112ca Original commit
squash 4fa167b80 Address feedback 1
squash 7d54e15ee Address feedback 2
以上编辑操作会压缩提交 4fa167b80 Address feedback 1 和 7d54e15ee Address feedback 2
到 d875112ca Original commit 中,只留下 d875112ca Original commit 成为时间线中的一部分。
保存文件并退出编辑器。
推送压缩后的提交:
git push --force-with-lease origin <branch_name>
贡献到其他仓库 Kubernetes 项目 包含大约 50 多个仓库。
这些仓库中很多都有文档:提供给最终用户的帮助文本、错误信息、API 参考或者代码注释等。
如果你发现有些文本需要改进,可以使用 GitHub 来搜索 Kubernetes 组织下的所有仓库。
这样有助于发现要在哪里提交 Issue 或 PR。
每个仓库有其自己的流程和过程。在登记 Issue 或者发起 PR 之前,记得阅读仓库的
README.md、CONTRIBUTING.md 和 code-of-conduct.md 文件,如果有的话。
大多数仓库都有自己的 Issue 和 PR 模版。通过查看一些待解决的 Issues 和
PR,也可以添加对它们的链接。你可以多少了解该团队的流程。
在登记 Issue 或提出 PR 时,务必尽量填充所给的模版,多提供详细信息。
接下来 7.2.3 - 为发行版本撰写功能特性文档 Kubernetes 的每个主要版本发布都会包含一些需要文档说明的新功能。
新的发行版本也会对已有功能特性和文档(例如将某功能特性从 alpha 升级为
beta)进行更新。
通常,负责某功能特性的 SIG 要为功能特性的文档草拟文档,并针对 kubernetes/website
仓库的合适的开发分支发起拉取请求。
SIG Docs 团队会提供文字方面的反馈意见,或者直接编辑文档草稿。
本节讨论两个小组在分支方面和发行期间所遵从的流程方面的约定。
对于文档贡献者 一般而言,文档贡献者不会为某个发行版本从头撰写文档。
相反,他们会与开发该功能特性的 SIG 团队一起,对文档草稿进行润色,
使之符合发布条件。
在你选定了某个功能特性,为其撰写文档(主笔或辅助),请在 #sig-docs Slack 频道、SIG Docs 的每周例会上,
或者在功能特性对应的 PR 上提出咨询。
如果继续工作是没有问题的,你可以使用
向他人的 PR 中提交
中描述的技术之一,参与 PR 的编辑工作。
了解即将发布的功能特性 要了解即将发布的功能特性,可以参加每周的 SIG Release 例会
(参考社区 页面,了解即将召开的会议),
监视 kubernetes/sig-release
中与发行相关的文档。
每个发行版本在
/sig-release/tree/master/releases/
下都有一个对应的子目录。
该子目录包含了发行版本的时间计划、发行公告的草稿以及列举发行团队名单的文档。
发行时间计划文件中包含到所有其他文档、会议、会议记录及发行相关的里程碑的链接。
其中也包含关于发行版本的目标列表、时间线,以及当前发行版本中就绪的特殊流程的信息。
文档末尾附近定义了若干与该发行版本有关的术语。
此文档也包含到 功能特性跟踪清单 的链接。
这一清单是了解哪些功能特性计划进入某发行版本的正式途径。
发行团队文档列举了哪些人扮演着各个发行版本的不同角色。
如果不清楚要联系谁来讨论特定的功能特性或者回答你的问题,
你可以参加发行团队的会议,提出你的问题,或者联系发行团队的牵头人,
这样他们就可以帮你找到正确的联系人。
发行说明草稿是用来发现与特定发行版本相关的功能特性、变更、废弃以及其他信息的好来源。
由于在发行周期的后段该文档的内容才会最终定稿,参考其中的信息时请谨慎。
特性跟踪清单 针对给定 Kubernetes 发行版本
特性跟踪清单中列举的是计划包含于该版本中的每个功能特性。
每一行中都包含特性的名称、特性对应的主要 GitHub Issue,其稳定性级别(ALpha、
Beta 或 Stable)、负责实现该特性的 SIG 和个人、是否该特性需要文档、该特性的
发行说明草稿以及该特性是否已经被合并等等。阅读此清单时请注意:
Beta 和 Stable 功能特性通常比 Alpha 特性更为需要文档支持。 如果某功能特性尚未被合并,就很难测试或者为其撰写文档。
对于对应的 PR 而言,也很难讲特性是否完全实现。 确定某个功能特性是否需要对应的文档的过程是一个手动的过程。
即使某个功能特性没有标记需要文档,并不意味着该功能真的不需要任何文档。 针对开发人员或其他 SIG 成员 本节中的信息是针对为发行版本中新功能特性撰写文档的来自其他 Kubernetes SIGs
的成员。
如果你是某个 SIG 的成员,负责为 Kubernetes 开发某一项新的功能特性,你需要与
SIG Docs 一起工作,确保这一新功能在发行之前已经为之撰写文档。
请参考特性跟踪清单
或者 Kubernetes Slack 上的 #sig-release 频道,检查时间安排的细节以及截止日期。
提交占位 PR 在 kubernetes/website 仓库上针对 dev-1.25
分支提交一个 PR,其中包含较少的、待以后慢慢补齐的提交内容。 编辑拉取请求描述以包括指向 kubernetes/kubernetes PR
和 kubernetes/enhancements 问题的链接。 使用 Prow 命令 /milestone 1.25
将 PR指派到对应的里程碑。这样做会提醒负责管理对应发行版本的文档团队成员,有
新的功能特性要合并到将来版本。 如果对应的功能特性不需要任何类型的文档变更,请通过在 #sig-release Slack
频道声明这一点以确保 sig-release 团队了解。
如果功能特性确实需要文档,而没有对应的 PR
提交,该功能特性可能会被从里程碑中移除。
PR 准备好评阅 时机成熟时,你可以在你的占位 PR 中完成功能特性文档。
尽可能为功能特性提供详尽文档以及使用说明。如果你需要文档组织方面的帮助,请
在 #sig-docs Slack 频道中提问。
当你已经完成内容撰写,指派给你的功能特性的文档贡献者会去评阅文档。
为了确保技术准确性,内容可能还需要相应 SIG 的技术审核。
尽量利用他们所给出的建议,改进文档内容以达到发布就绪状态。
如果你的功能特性需要文档,而一直没有关于该特性的文档提交评阅,
该特性可能会被从里程碑中移除。
所有 PR 均经过评审且合并就绪 如果你的 PR 在发行截止日期之前尚未合并到 dev-1.25 分支,
请与负责管理该发行版本的文档团队成员一起合作,在截止期限之前将其合并。
如果功能特性需要文档,而文档并未就绪,该特性可能会被从里程碑中去除。
如果你的功能特性是 Alpha 阶段,并且受到某个特性门控的保护,在你的 PR 中,请确保将
该特性门控添加到
Alpha/Beta 特性门控
表格中。
如果你的功能特性不再是 Alpha 阶段,请确保特性门控状态得到更新。
7.2.4 - 提交博客和案例分析 任何人都可以撰写博客并提交评阅。
案例分析则在被批准之前需要更多的评阅。
Kubernetes 博客 Kubernetes 博客用于项目发布新功能特性、社区报告以及其他一些可能对整个社区
很重要的新闻。
其读者包括最终用户和开发人员。
大多数博客的内容是关于核心项目中正在发生的事情,不过我们也鼓励你提交一些
关于生态系统中其他地方发生的事情的博客。
任何人都可以撰写博客并提交评阅。
指导原则和期望 博客内容不可以是销售用语。文章内容必须是对整个 Kubernetes 社区中很多人都有参考意义。
例如,所提交的文章应该关注上游的 Kubernetes 项目本身,而不是某个厂商特定的配置。
请参阅文档风格指南
以了解哪些内容是 Kubernetes 所允许的。 链接应该主要指向官方的 Kubernetes 文档。
当引用外部信息时,链接应该是多样的。
例如,所提交的博客文章中不可以只包含指向某个公司的博客的链接。 有些时候,这是一个比较棘手的权衡过程。
博客团队 的存在目的即是为
Kubernetes 博客提供文章是否合适的指导意见。
所以,需要帮助的时候不要犹豫。 博客内容并非在某特定日期发表。文章会交由社区自愿者评阅。我们会尽力满足特定的时限要求,只是无法就此作出承诺。 Kubernetes 项目的很多核心组件会在发布窗口期内提交博客文章,导致发表时间被推迟。
因此,请考虑在发布周期内较为平静的时间段提交博文。 如果你希望就博文发表日期上进行较大范围的协调,请联系
CNCF 推广团队 。
这也许是比提交博客文章更合适的一种选择。 有时,博客的评审可能会堆积起来。如果你觉得你的文章没有引起该有的重视,
你可以通过此 Slack 频道
联系博客团队,以获得实时反馈。 博客内容应该对 Kubernetes 用户有用。与参与 Kubernetes SIGs 活动相关,或者与这类活动的结果相关的主题通常是切题的。
请参考上游推广团队 的工作以获得对此类博文的支持。 Kubernetes 的组件都有意设计得模块化,因此使用类似 CNI、CSI 等集成点的工具
通常都是切题的。 关于其他 CNCF 项目的博客可能切题也可能不切题。
我们建议你在提交草稿之前与博客团队联系。很多 CNCF 项目有自己的博客。这些博客通常是更好的选择。
有些时候,某个 CNCF 项目的主要功能特性或者里程碑的变化可能是用户有兴趣在
Kubernetes 博客上阅读的内容。 博客文章应该是原创内容。官方博客的目的不是将某第三方已发表的内容重新作为新内容发表。 博客的授权协议
的确允许出于商业目的来使用博客内容;但并不是所有可以商用的内容都适合在这里发表。 博客文章的内容应该在一段时间内不过期。考虑到项目的开发速度,我们希望读者看到的是不必更新就能保持长期准确的内容。 有时候,在官方文档中添加一个教程或者进行内容更新都是比博客更好的选择。可以考虑在博客文章中将较长技术内容的重点放在鼓励读者自行尝试上,或者
放在问题域本身或者为什么读者应该关注某个话题上。 提交博客的技术考虑 所提交的内容应该是 Markdown 格式的,以便能够被Hugo 生成器来处理。
关于如何使用相关技术,有很多可用的资源 。
我们知道这一需求可能给那些对此过程不熟悉的朋友们带来不便,
我们也一直在寻找降低难度的解决方案。
如果你有降低难度的好主意,请自荐帮忙。
SIG Docs 博客子项目 负责管理博客的评阅过程。
更多信息可参考提交博文 。
要提交博文,你可以遵从以下指南:
第一个或者最初的提交的描述信息中应该包含一个所作工作的简单摘要,
并作为整个博文的一个独立描述。
请注意,对博文的后续修改编辑都会最终合并到此主提交中,所以此提交的描述信息
应该尽量有用。较好的提交消息(Commit Message)示例:Add blog post on the foo kubernetes feature blog: foobar announcement 较差的提交消息示例:Add blog post . initial commit draft post 博客团队会对 PR 内容进行评阅,为你提供一些评语以便修订。
之后,机器人会将你的博文合并并发表。 提交案例分析 案例分析用来概述组织如何使用 Kubernetes 解决现实世界的问题。
Kubernetes 市场化团队和 CNCF 成员
会与你一起工作,撰写所有的案例分析。
请查看
现有案例分析
的源码。
参考案例分析指南
根据指南中的注意事项提交你的 PR 请求。
7.3.1 - 评阅 PRs 任何人均可评阅文档的拉取请求。访问 Kubernetes 网站仓库的
pull requests
部分可以查看所有待处理的拉取请求(PRs)。
评阅文档 PR 是将你自己介绍给 Kubernetes 社区的一种很好的方式。
它将有助于你学习代码库并与其他贡献者之间建立相互信任关系。
在评阅之前,可以考虑:
准备工作 在你开始评阅之前:
阅读 CNCF 行为准则
确保你会始终遵从其中约定; 保持有礼貌、体谅他人,怀助人为乐初心; 评论时若给出修改建议,也要兼顾 PR 的积极方面 保持同理心,多考虑他人收到评阅意见时的可能反应 假定大家都是好意的,通过问问题澄清意图 如果你是有经验的贡献者,请考虑和新贡献者一起合作,提高其产出质量 评阅过程 一般而言,应该使用英语来评阅 PR 的内容和样式。
前往 https://github.com/kubernetes/website/pulls ,
你会看到所有针对 Kubernetes 网站和文档的待处理 PRs。
使用以下标签(组合)对待处理 PRs 进行过滤:
cncf-cla: yes (建议):由尚未签署 CLA 的贡献者所发起的 PRs 不可以合并。
参考签署 CLA 以了解更多信息。language/en (建议):仅查看英语语言的 PRs。size/<尺寸>:过滤特定尺寸(规模)的 PRs。如果你刚入门,可以从较小的 PR 开始。此外,确保 PR 没有标记为尚未完成(Work in Progress)。
包含 work in progress 的 PRs 通常还没准备好被评阅。
选定 PR 评阅之后,可以通过以下方式理解所作的变更:
阅读 PR 描述以理解所作变更,并且阅读所有关联的 Issues 阅读其他评阅人给出的评论 点击 Files changed Tab 页面,查看被改变的文件和代码行 滚动到 Conversation Tab 页面下端的 PR 构建检查节区,点击
deploy/netlify 行的 Details 链接,预览 Netlify
预览构建所生成的结果 前往 Files changed Tab 页面,开始你的评阅工作
点击你希望评论的行旁边的 + 号 填写你对该行的评论,之后或者选择Add single comment (如果你只有一条评论)
或者 Start a review (如果你还有其他评论要添加) 评论结束时,点击页面顶部的 Review changes 。这里你可以添加你的评论结语
(记得留下一些正能量的评论!)、根据需要批准 PR、请求作者进一步修改等等。
新手应该选择 Comment 。 评阅清单 评阅 PR 时可以从下面的条目入手。
语言和语法 是否存在明显的语言或语法错误?对某事的描述有更好的方式? 是否存在一些过于复杂晦涩的用词,本可以用简单词汇来代替? 是否有些用词、术语或短语可以用不带歧视性的表达方式代替? 用词和大小写方面是否遵从了样式指南 ? 是否有些句子太长,可以改得更短、更简单? 是否某些段落过长,可以考虑使用列表或者表格来表达? 内容 Kubernetes 网站上是否别处已经存在类似的内容? 内容本身是否过度依赖于网站范畴之外、独立供应商或者非开源的文档? 网站 PR 是否改变或者删除了某页面的标题、slug/别名或者链接锚点?
如果是这样,PR 是否会导致出现新的失效链接?
是否有其他的办法,比如改变页面标题但不改变其 slug? PR 是否引入新的页面?如果是:该页面是否使用了正确的页面内容类型
及相关联的 Hugo 短代码(shortcodes)? 该页面能否在对应章节的侧面导航中显示?显示得正确么? 该页面是否应出现在网站主页面 的列表中? 变更是否正确出现在 Netlify 预览中了?
要对列表、代码段、表格、注释和图像等元素格外留心 其他 对于 PR 中的小问题,例如拼写错误或者空格问题,可以在你的评论前面加上 nit:。
这样做可以让作者知道该问题不是一个不得了的大问题。
7.3.2 - 评阅人和批准人文档 SIG Docs
评阅人(Reviewers)
和批准人(Approvers)
在对变更进行评审时需要做一些额外的事情。
每周都有一个特定的文档批准人自愿负责对 PR 进行分类和评阅。
此角色称作该周的“PR 管理者(PR Wrangler)”。
相关信息可参考 PR Wrangler 排班表 。
要成为 PR Wangler,需要参加每周的 SIG Docs 例会,并自愿报名。
即使当前这周排班没有轮到你,你仍可以评阅那些尚未被积极评阅的 PRs。
除了上述的轮值安排,后台机器人也会为基于所影响的文件来为 PR
指派评阅人和批准人。
评阅 PR Kubernetes 文档遵循 Kubernetes 代码评阅流程 。
评阅 PR 文档中所描述的所有规程都适用,
不过评阅人和批准人还要做以下工作:
根据需要使用 Prow 命令 /assign 指派特定的评阅人。如果某个 PR
需要来自代码贡献者的技术审核时,这一点非常重要。
说明: 你可以查看 Markdown 文件的文件头,其中的 reviewers 字段给出了哪些人可以为文档提供技术审核。
确保 PR 遵从内容指南 和样式指南 ;
如果 PR 没有达到要求,指引作者阅读指南中的相关部分。
适当的时候使用 GitHub Request Changes 选项,建议 PR 作者实施所建议的修改。
当你所提供的建议被采纳后,在 GitHub 中使用 /approve 或 /lgtm Prow 命令,改变评审状态。
提交到他人的 PR 为 PR 留下评语是很有用的,不过有时候你需要向他人的 PR 提交内容。
除非他人明确请求你的帮助或者你希望重启一个被放弃很久的 PR,不要“接手”他人的工作。
尽管短期看来这样做可以提高效率,但是也剥夺了他人提交贡献的机会。
你所要遵循的流程取决于你需要编辑已经在 PR 范畴的文件,还是 PR 尚未触碰的文件。
如果处于下列情况之一,你不可以向别人的 PR 提交内容:
评阅用的 Prow 命令 Prow
是基于 Kubernetes 的 CI/CD 系统,基于拉取请求(PR)的触发运行不同任务。
Prow 使得我们可以使用会话机器人一样的命令跨整个 Kubernetes 组织处理 GitHub
动作,例如添加和删除标签 、关闭 Issues
以及指派批准人等等。你可以使用 /<命令名称> 的形式以 GitHub 评论的方式输入
Prow 命令。
评阅人和批准人最常用的 Prow 命令有:
评阅用 Prow 命令 Prow 命令 角色限制 描述 /lgtm任何人均可使用,但只有评阅人和批准人使用此命令的时候才会触发自动化操作 用来表明你已经完成 PR 的评阅并对其所作变更表示满意 /approve批准人 批准某 PR 可以合并 /assign评阅人或批准人 指派某人来评阅或批准某 PR /close评阅人或批准人 关闭 Issue 或 PR /hold任何人 添加 do-not-merge/hold 标签,用来表明 PR 不应被自动合并 /hold cancel任何人 去掉 do-not-merge/hold 标签
请参考 Prow 命令指南 ,了解你可以在 PR
中使用的命令的完整列表。
对 Issue 进行诊断和分类 一般而言,SIG Docs 遵从 Kubernetes issue 判定 流程并使用相同的标签。
此 GitHub Issue
过滤器
可以用来查找需要评判的 Issues。
评判 Issue 验证 Issue 的合法性 确保 Issue 是关于网站文档的。某些 Issue 可以通过回答问题或者为报告者提供
资源链接来快速关闭。
参考请求支持或代码缺陷报告
节以了解详细信息。 评估该 Issue 是否有价值。 如果 Issue 缺少足够的细节以至于无法采取行动,或者报告者没有通过模版提供
足够信息,可以添加 triage/needs-information 标签。 如果 Issue 同时标注了 lifecycle/stale 和 triage/needs-information
标签,可以直接关闭。 添加优先级标签(
Issue 判定指南 中有优先级标签的详细定义) Issue 标签 标签 描述 priority/critical-urgent应马上处理 priority/important-soon应在 3 个月内处理 priority/important-longterm应在 6 个月内处理 priority/backlog可无限期地推迟,可在人手充足时处理 priority/awaiting-more-evidence占位符,标示 Issue 可能是一个不错的 Issue,避免该 Issue 被忽略或遗忘 help or good first issue适合对 Kubernetes 或 SIG Docs 经验较少的贡献者来处理。更多信息可参考需要帮助和入门候选 Issue 标签 。
基于你自己的判断,你可以选择某 Issue 来处理,为之发起 PR
(尤其是那些可以很快处理或与你已经在做的工作相关的 Issue)。
如果你对 Issue 评判有任何问题,可以在 #sig-docs Slack 频道或者
kubernetes-sig-docs 邮件列表
中提问。
添加和删除 Issue 标签 要添加标签,可以用以下形式对 PR 进行评论:
/<要添加的标签> (例如, /good-first-issue)/<标签类别> <要添加的标签> (例如,/triage needs-information 或 /language ja)要移除某个标签,可以用以下形式对 PR 进行评论:
/remove-<要移除的标签> (例如,/remove-help)/remove-<标签类别> <要移除的标签> (例如,/remove-triage needs-information)在以上两种情况下,标签都必须合法存在。如果你尝试添加一个尚不存在的标签,
对应的命令会被悄悄忽略。
关于所有标签的完整列表,可以参考
Website 仓库的标签节 。
实际上,SIG Docs 并没有使用全部标签。
Issue 生命周期标签 Issues 通常都可以快速创建并关闭。
不过也有些时候,某个 Issue 被创建之后会长期处于非活跃状态。
也有一些时候,即使超过 90 天,某个 Issue 仍应保持打开状态。
Issue 生命周期标签 标签 描述 lifecycle/stale过去 90 天内某 Issue 无人问津,会被自动标记为停滞状态。如果 Issue 没有被 /remove-lifecycle stale 命令重置生命期,就会被自动关闭。 lifecycle/frozen对应的 Issue 即使超过 90 天仍无人处理也不会进入停滞状态。用户手动添加此标签给一些需要保持打开状态超过 90 天的 Issue,例如那些带有 priority/important-longterm 标签的 Issue。
处理特殊的 Issue 类型 SIG Docs 常常会遇到以下类型的 Issue,因此对其处理方式描述如下。
重复的 Issue 如果针对同一个问题有不止一个打开的 Issue,可以将其合并为一个 Issue。
你需要决定保留哪个 Issue 为打开状态(或者重新登记一个新的 Issue),
然后将所有相关的信息复制过去并提供对关联 Issues 的链接。
最后,将所有其他描述同一问题的 Issue 标记为 triage/duplicate 并关闭之。
保持只有一个 Issue 待处理有助于减少困惑,避免在同一问题上发生重复劳动。
失效链接 Issues 如果失效链接是关于 API 或者 kubectl 文档的,可以将其标记为
/priority critical-urgent,直到问题原因被弄清楚为止。
对于其他的链接失效问题,可以标记 /priority important-longterm,
因为这些问题都需要手动处理。
博客问题 我们预期 Kubernetes 博客 条目随着时间推移都会过期。
因此,我们只维护一年内的博客条目。
如果某个 Issue 是与某个超过一年的博客条目有关的,可以直接关闭
Issue,不必修复。
请求支持或代码缺陷报告 某些文档 Issues 实际上是关于底层代码的 Issue 或者在某方面请求协助的问题,
例如某个教程无法正常工作。
对于与文档无关的 Issues,关闭它并打上标签 kind/support,可以通过评论
告知请求者其他支持渠道(Slack、Stack Overflow)。
如果有相关的其他仓库,可以告诉请求者应该在哪个仓库登记与功能特性相关的 Issues
(通常会是 kubernetes/kubernetes)。
下面是对支持请求的回复示例:
This issue sounds more like a request for support and less
like an issue specifically for docs. I encourage you to bring
your question to the `#kubernetes-users` channel in
[Kubernetes slack](https://slack.k8s.io/). You can also search
resources like
[Stack Overflow](https://stackoverflow.com/questions/tagged/kubernetes)
for answers to similar questions.
You can also open issues for Kubernetes functionality in
https://github.com/kubernetes/kubernetes.
If this is a documentation issue, please re-open this issue.
对代码缺陷 Issue 的回复示例:
This sounds more like an issue with the code than an issue with
the documentation. Please open an issue at
https://github.com/kubernetes/kubernetes/issues.
If this is a documentation issue, please re-open this issue.
7.4 - 本地化 Kubernetes 文档 此页面描述如何为其他语言的文档提供
本地化 版本。
起步 由于贡献者无法批准他们自己的请求,因此您至少需要两个贡献者才能开始本地化。
所有本地化团队必须使用自身的资源持续工作。我们很高兴托管你的产出,但无法为你翻译。
找到两个字母的语言代码 首先,有关本地化的两个字母的国家代码,请参考
ISO 639-1 标准 。
例如,韩国的两个字母代码是 ko。
派生(fork)并且克隆仓库 首先,为 kubernetes/website 仓库
创建你自己的副本 。
然后,克隆你的 website 仓库副本并通过 cd 命令进入 website 目录:
git clone https://github.com/<username>/website
cd website
发起拉取请求(PR) 接下来,提交 PR 请求 ,
将本地化添加到 kubernetes/website 仓库。
该 PR 必须包含所有最低要求的内容 ,然后才能被批准。
有关添加新本地化的示例,请参见添加法语文档 的 PR。
加入到 Kubernetes GitHub 组织 提交本地化 PR 后,你可以成为 Kubernetes GitHub 组织的成员。
团队中的每个人都需要在 kubernetes/org 仓库中创建自己的
组织成员申请 。
在 GitHub 中添加你的本地化团队 接下来,将你的 Kubernetes 本地化团队添加到
sig-docs/teams.yaml 。
有关添加本地化团队的示例,请参见添加西班牙本地化团队 的 PR。
@kubernetes/sig-docs-**-owners 成员可以批准更改对应本地化目录 /content/**/ 中内容的 PR,并仅限这类 PR。
@kubernetes/sig-docs-**-reviews 团队被自动分派新 PR 的审阅任务。
@kubernetes/website-maintainers 成员可以创建新的开发分支来协调翻译工作。
@kubernetes/website-milestone-maintainers 成员可以使用 /milestone
Prow 命令 为 issues 或 PR 设定里程碑。
接下来,在 kubernetes/test-infra 仓库中为您的本地化添加一个 GitHub 标签。
标签可让您过滤 issues 和针对特定语言的 PR。
有关添加标签的示例,请参见添加意大利语标签 的 PR。
寻找社区 让 Kubernetes SIG Docs 知道你对创建本地化感兴趣!
加入SIG Docs Slack 频道 。
其他本地化团队很乐意帮助你起步并回答你的任何问题。
你还可以在 kubernetes/community 仓库中为你的本地化创建一个 Slack 频道。
有关添加 Slack 频道的示例,请参见为印尼语和葡萄牙语添加频道 的 PR。
最低要求内容 修改站点配置 Kubernetes 网站使用 Hugo 作为其 Web 框架。网站的 Hugo 配置位于
config.toml 文件中。
为了支持新的本地化,您需要修改 config.toml。
在现有的 [languages] 下,将新语言的配置添加到 config.toml 中。
例如,下面是德语的配置示例:
[languages.de]
title = "Kubernetes"
description = "Produktionsreife Container-Verwaltung"
languageName = "Deutsch"
contentDir = "content/de"
weight = 3
为你的语言块分配一个 weight 参数时,找到权重最高的语言块并将其加 1。
有关 Hugo 多语言支持的更多信息,请参阅"多语言模式 "。
添加一个新的本地化目录 将特定语言的子目录添加到仓库中的
content 文件夹下。
例如,德语的两个字母的代码是 de:
本地化社区行为准则 在 cncf/foundation
仓库提交 PR,添加你所用语言版本的行为准则。
添加本地化的 README 文件 为了指导其他本地化贡献者,请在 k/website 的根目录添加一个新的
README-**.md ,
其中 ** 是两个字母的语言代码。例如,德语 README 文件为 README-de.md。
在本地化的 README-**.md 文件中为本地化贡献者提供指导。包含 README.md 中包含的相同信息,以及:
创建本地化的 README 文件后,请在英语版文件 README.md 中添加指向该文件的链接,
并给出英文形式的联系信息。你可以提供 GitHub ID、电子邮件地址、
Slack 频道 或其他联系方式。你还必须提供指向本地化的社区行为准则的链接。
设置 OWNERS 文件 要设置每个对本地化做出贡献用户的角色,请在特定于语言的子目录内创建一个 OWNERS 文件,其中:
reviewers : 具有评审人角色的 kubernetes 团队的列表,在本例中为在
在 GitHub 中添加您的本地化团队
中创建的 sig-docs-**-reviews 团队。approvers : 具有批准人角色的 kubernetes 团队的列表,在本例中为在
在 GitHub 中添加您的本地化团队
中创建的 sig-docs-**-owners 团队。labels : 可以自动应用于 PR 的 GitHub 标签列表,在本例中为
配置工作流程 中创建的语言标签。有关 OWNERS 文件的更多信息,请访问go.k8s.io/owners 。
语言代码为 es 的西班牙语 OWNERS 文件 看起来像:
# See the OWNERS docs at https://go.k8s.io/owners
# This is the localization project for Spanish.
# Teams and members are visible at https://github.com/orgs/kubernetes/teams.
reviewers :
- sig-docs-es-reviews
approvers :
- sig-docs-es-owners
labels :
- language/es
添加了特定语言的 OWNERS 文件之后,使用新的 Kubernetes 本地化团队、
sig-docs-**-owners 和 sig-docs-**-reviews 列表更新
根目录下的 OWNERS_ALIAES 文件。
对于每个团队,请按字母顺序添加
在 GitHub 中添加您的本地化团队
中所请求的 GitHub 用户列表。
--- a/OWNERS_ALIASES
+++ b/OWNERS_ALIASES
@@ -48,6 +48,14 @@ aliases:
- stewart-yu
- xiangpengzhao
- zhangxiaoyu-zidif
+ sig-docs-es-owners: # Admins for Spanish content
+ - alexbrand
+ - raelga
+ sig-docs-es-reviews: # PR reviews for Spanish content
+ - alexbrand
+ - electrocucaracha
+ - glo-pena
+ - raelga
sig-docs-fr-owners: # Admins for French content
- perriea
- remyleone
翻译文档 本地化所有 Kubernetes 文档是一项艰巨的任务。从小做起,循序渐进。
所有本地化至少必须包括:
翻译后的文档必须保存在自己的 content/**/ 子目录中,否则将遵循与英文源相同的 URL 路径。
例如,要准备将 Kubernetes 基础 教程翻译为德语,
请在 content/de/ 文件夹下创建一个子文件夹并复制英文源:
mkdir -p content/de/docs/tutorials
cp content/en/docs/tutorials/kubernetes-basics.md content/de/docs/tutorials/kubernetes-basics.md
翻译工具可以加快翻译过程。例如,某些编辑器提供了用于快速翻译文本的插件。
注意: 机器生成的翻译不能达到最低质量标准,需要进行大量人工审查才能达到该标准。
为了确保语法和含义的准确性,本地化团队的成员应在发布之前仔细检查所有由机器生成的翻译。
源文件 本地化必须基于最新版本 v1.24 中的英文文件。
要查找最新版本的源文件:
导航到 Kubernetes website 仓库,网址为 https://github.com/kubernetes/website 。 选择最新版本的 release-1.X 分支。 最新版本是 v1.24,所以最新的发行分支是
release-1.24 。
i18n/ 中的网站字符串 本地化必须在新的语言特定文件中包含
i18n/en.toml
的内容。以德语为例:i18n/de.toml。
将新的本地化文件添加到 i18n/。例如德语 (de):
cp i18n/en.toml i18n/de.toml
然后翻译每个字符串的值:
[docs_label_i_am]
other = "ICH BIN..."
本地化网站字符串允许你自定义网站范围的文本和特性:例如,每个页面页脚中的合法版权文本。
特定语言的样式指南和词汇表 一些语言团队有自己的特定语言样式指南和词汇表。
例如,请参见中文本地化指南 。
分支策略 因为本地化项目是高度协同的工作,所以我们鼓励团队基于共享的开发分支工作。
在开发分支上协作需要:
@kubernetes/website-maintainers
中的团队成员从 https://github.com/kubernetes/website 原有分支新建一个开发分支。
当你给 kubernetes/org 仓库添加你的本地化团队 时,
你的团队批准人便加入了 @kubernetes/website-maintainers 团队。
我们推荐以下分支命名方案:
dev-<source version>-<language code>.<team milestone>
例如,一个德语本地化团队的批准人基于 Kubernetes v1.12 版本的源分支,
直接新建了 k/website 仓库的开发分支 dev-1.12-de.1。
个人贡献者基于开发分支创建新的特性分支
例如,一个德语贡献者新建了一个拉取请求,并将 username:local-branch-name 更改为 kubernetes:dev-1.12-de.1。
批准人审查功能分支并将其合并到开发分支中。
批准人会定期发起并批准新的 PR,将开发分支合并到其源分支。在批准 PR 之前,请确保先 squash commits。
根据需要重复步骤 1-4,直到完成本地化工作。例如,随后的德语开发分支将是:
dev-1.12-de.2、dev-1.12-de.3,等等。
团队必须将本地化内容合入到发布分支中,该发布分支也正是内容的来源。
例如,源于 release-1.24 的开发分支必须基于 release-1.24。
approver 必须通过使开发分支与源分支保持最新并解决合并冲突来维护开发分支。
开发分支的存在时间越长,通常需要的维护工作就越多。
考虑定期合并开发分支并新建分支,而不是维护一个持续时间很长的开发分支。
在团队每个里程碑的起点,创建一个 issue 来比较先前的开发分支和当前的开发分支之间的上游变化很有帮助。
虽然只有批准人才能创建新的开发分支并合并 PR,但任何人都可以为新的开发分支提交一个拉取请求(PR)。
不需要特殊权限。
有关基于派生或直接从仓库开展工作的更多信息,请参见 "派生和克隆" 。
上游贡献 Sig Docs 欢迎对英文原文的上游贡献和修正。
帮助现有的本地化 您还可以向现有本地化添加或改进内容提供帮助。
加入本地化团队的 Slack 频道 ,
然后开始新建 PR 来提供帮助。
请限制每个 PR 只涉及一种语言,这是因为更改多种语言版本内容的 PR
可能非常难审阅。
接下来 本地化满足工作流程和最低输出要求后,SIG 文档将:
7.5 - 参与 SIG Docs SIG Docs 是 Kubernetes 项目
特别兴趣小组
中的一个,负责编写、更新和维护 Kubernetes 的总体文档。
参见社区 GitHub 仓库中 SIG Docs
以进一步了解该 SIG。
SIG Docs 欢迎所有贡献者提供内容和审阅。任何人可以提交拉取请求(PR)。
欢迎所有人对文档内容创建 Issue 和对正在处理中的 PR 进行评论。
你也可以成为成员(member) 、
评阅人(reviewer) 或者
批准人(approver) 。
这些角色拥有更高的权限,且需要承担批准和提交变更的责任。
有关 Kubernetes 社区中的成员如何工作的更多信息,请参见
社区成员身份 。
本文档的其余部分概述了这些角色在 SIG Docs 中发挥作用的一些独特方式。
SIG Docs 负责维护 Kubernetes 最面向公众的方面之一 —— Kubernetes 网站和文档。
SIG Docs 主席 每个 SIG,包括 SIG Docs,都会选出一位或多位成员作为主席。
主席会成为 SIG Docs 和其他 Kubernetes 组织的联络接口人。
他们需要了解整个 Kubernetes 项目的架构,并明白 SIG Docs 如何在其中运作。
如需查询当前的主席名单,请查阅
领导人员 。
SIG Docs 团队和自动化 SIG 文档中的自动化服务依赖于两种不同的自动化机制:
GitHub 组和 OWNERS 文件。
GitHub 团队 GitHub 上有两类 SIG Docs 团队:
@sig-docs-{language}-owners 包含批准人和牵头人@sig-docs-{language}-reviewers 包含评阅人可以在 GitHub 的评论中使用团队的名称 @name 来与团队成员沟通。
有时候 Prow 所定义的团队和 GitHub 团队有所重叠,并不完全一致。
对于指派 Issue、PR 和批准 PR,自动化工具使用来自 OWNERS 文件的信息。
OWNERS 文件和扉页 Kubernetes 项目使用名为 prow 的自动化工具来自动处理 GitHub issue 和 PR。
Kubernetes website 仓库 使用了两个
prow 插件 :
这两个插件使用位于 kubernetes/website 仓库顶层的
OWNERS 文件和
OWNERS_ALIASES
文件来控制 prow 在仓库范围的工作方式。
OWNERS 文件包含 SIG Docs 评阅人和批准人的列表。
OWNERS 文件也可以存在于子目录中,可以在子目录层级重新设置哪些人可以作为评阅人和
批准人,并将这一设定传递到下层子目录。
关于 OWNERS 的更多信息,请参考
OWNERS
文档。
此外,每个独立的 Markdown 文件都可以在其前言部分列出评阅人和批准人,
每一项可以是 GitHub 用户名,也可以是 GitHub 组名。
结合 OWNERS 文件及 Markdown 文件的前言信息,自动化系统可以给 PR 作者可以就应该
向谁请求技术和文字评阅给出建议。
PR 是怎样被合并的 当某个拉取请求(PR)被合并到用来发布内容的分支,对应的内容就会被发布到 http://kubernetes.io 。
为了确保我们所发布的内容的质量足够好,合并 PR 的权限仅限于
SIG Docs 批准人。下面是合并的工作机制:
当某个 PR 同时具有 lgtm 和 approve 标签,没有 hold 标签且通过所有测试时,
该 PR 会被自动合并。 Kubernetes 组织的成员和 SIG Docs 批准人可以添加评论以阻止给定 PR 的自动合并,
即通过 /hold 评论或者收回某个 /lgtm 评论实现这点。 所有 Kubernetes 成员可以通过 /lgtm 评论添加 lgtm 标签。 只有 SIG Docs 批准人可以通过评论 /approve 合并 PR。
某些批准人还会执行一些其他角色,例如
PR 管理者 或
SIG Docs 主席 等。 接下来 关于贡献 Kubernetes 文档的更多信息,请参考:
7.5.1 - 角色与责任 任何人都可以为 Kubernetes 作出贡献。随着你对 SIG Docs 的贡献增多,你可以申请
社区内不同级别的成员资格。
这些角色使得你可以在社区中承担更多的责任。
每个角色都需要更多的时间和投入。具体包括:
任何人(Anyone):为 Kubernetes 文档作出贡献的普通贡献者。 成员(Members):可以对 Issue 进行分派和判别,对 PR 提出无约束性的评审意见。 评审人(Reviewers):可以领导对文档 PR 的评审,可以对变更的质量进行判别。 批准人(Approvers):可以领导对文档的评审并合并变更。 任何人(Anyone) 任何拥有 GitHub 账号的人都可以对 Kubernetes 作出贡献。SIG Docs
欢迎所有新的贡献者。
任何人都可以:
在签署了 CLA 之后,任何人还可以:
发起拉取请求(PR),改进现有内容、添加新内容、撰写博客或者案例分析 创建示意图、图形资产或者嵌入式的截屏和视频内容 进一步的详细信息,可参见贡献新内容 。
成员(Members) 成员是指那些对 kubernetes/website 提交很多拉取请求(PR)的人。
成员都要加入 Kubernetes GitHub 组织 。
成员可以:
成为一个成员 在你成功地提交至少 5 个 PR 并满足
相关条件
之后:
找到两个评审人 或批准人 为你的成员身份提供
担保 。
通过 Kubernetes Slack 上的 #sig-docs 频道 或者
SIG Docs 邮件列表
来寻找为你担保的人。
说明: 不要单独发送邮件给某个 SIG Docs 成员或在 Slack 中与其私聊。
在提交申请之前,一定要先确定担保人。
在 kubernetes/org 仓库
使用 Organization Membership Request Issue 模版登记一个 Issue。
告知你的担保人你所创建的 Issue,你可以:
在 Issue 中 @<GitHub-username> 提及他们的 GitHub 用户名 通过 Slack 或 email 直接发送给他们 Issue 链接 担保人会通过 +1 投票来批准你的请求。一旦你的担保人批准了该请求,
某个 Kubernetes GitHub 管理员会将你添加为组织成员。恭喜!
如果你的成员请求未被接受,你会收到一些反馈。
当处理完反馈意见之后,可以再次发起申请。
在你的邮件账户中接受来自 Kubernetes GitHub 组织发出的成员邀请。
说明: GitHub 会将邀请发送到你的账户中所设置的默认邮件地址。
评审人(Reviewers) 评审人负责评审悬决的 PR。
与成员所给的反馈不同,你必须处理评审人的反馈。
评审人是 @kubernetes/sig-docs-{language}-reviews GitHub 团队的成员。
评审人可以:
执行任何人 和成员 节所列举的操作
评审 PR 并提供具约束性的反馈信息
说明: 要提供非约束性的反馈,可以在你的评语之前添加 "Optionally: " 这样的说法。
编辑代码中用户可见的字符串
改进代码注释
你可以是 SIG Docs 的评审人,也可以是某个主题领域的文档的评审人。
为 PR 指派评审人 自动化引擎会为每个 PR 自动指派评审人。
你可以通过为 PR 添加评论 /assign [@_github_handle] 来请求某个特定评审人来评审。
如果所指派的评审人未能及时评审,其他的评审人也可以参与进来。
你可以根据需要指派技术评审人。
使用 /lgtm LGTM 代表的是 “Looks Good To Me (我觉得可以)”,用来标示某个 PR
在技术上是准确的,可以被合并。
所有 PR 都需要来自某评审人的 /lgtm 评论和来自某批准人的 /approve
评论。
来自评审人的 /lgtm 评论是具有约束性的,会触发自动化设施添加 lgtm 标签。
成为评审人 当你满足相关条件 时,
你可以成为一个 SIG Docs 评审人。
来自其他 SIG 的评审人必须为 SIG Docs 单独申请评审人资格。
申请过程如下:
发起 PR,将你的 GitHub 用户名添加到 kubernetes/website 仓库中
OWNERS_ALIASES
文件的特定节。
说明: 如果你不确定要添加到哪个位置,可以将自己添加到 sig-docs-en-reviews。
将 PR 指派给一个或多个 SIG Docs 批准人(sig-docs-{language}-owners
下列举的用户名)。
请求被批准之后,SIG Docs Leads 之一会将你添加到合适的 GitHub 团队。
一旦添加完成, @k8s-ci-robot
会在处理未来的 PR 时,将 PR 指派给你或者建议你来评审某 PR。
批准人(Approvers) 批准人负责评审和批准 PR 以将其合并。
批准人是 @kubernetes/sig-docs-{language}-owners GitHub 团队的成员。
批准人可以执行以下操作:
执行列举在任何人 、成员 和评审人 节区的操作 通过使用 /approve 评论来批准、合并 PRs,发布贡献者所贡献的内容。 就样式指南给出改进建议 对文档测试给出改进建议 对 Kubernetes 网站或其他工具给出改进建议 如果某个 PR 已有 /lgtm 标签,或者批准人再回复一个 /lgtm ,则这个 PR 会自动合并。
SIG Docs 批准人应该只在不需要额外的技术评审的情况下才可以标记 /lgtm。
批准 PR 只有批准人和 SIG Docs Leads 可以将 PR 合并到网站仓库。
这意味着以下责任:
批准人可以使用 /approve 命令将 PR 合并到仓库中。
警告: 不小心的合并可能会破坏整个站点。在执行合并操作时,务必小心。
确保所提议的变更满足贡献指南 要求
如果有问题或者疑惑,可以根据需要请他人帮助评审。
在 /approve PR 之前,须验证 Netlify 测试是否正常通过。
在批准之前,请访问 Netlify 的页面预览来确保变更内容可正常显示。
参与 PR 管理者轮值排班
执行时长为一周的 PR 管理。SIG Docs 期望所有批准人都参与到此轮值工作中。
更多细节可参见做一周的 PR 管理者 。
成为批准人 当你满足一定条件 时,可以成为一个 SIG Docs 批准人。
来自其他 SIGs 的批准人也必须在 SIG Docs 独立申请批准人资格。
申请流程如下:
发起一个 PR,将自己添加到 kubernetes/website 仓库中
OWNERS_ALIASES
文件的对应节区。
说明: 如果你不确定要添加到哪个位置,可以将自己添加到 sig-docs-en-owners 中。
将 PR 指派给一个或多个 SIG Docs 批准人。
请求被批准之后,SIG Docs Leads 之一会将你添加到对应的 GitHub 团队。
一旦添加完成, K8s-ci-robot
会在处理未来的 PR 时,将 PR 指派给你或者建议你来评审某 PR。
接下来 7.5.2 - PR 管理者 SIG Docs 的批准人(Approvers) 们每周轮流负责
管理仓库的 PRs 。
本节介绍 PR 管理者的职责。关于如何提供较好的评审意见,可参阅
评审变更 .
职责 在为期一周的轮值期内,PR 管理者要:
每天对新增的 Issues 判定和打标签。参见
对 Issues 进行判定和分类
以了解 SIG Docs 如何使用元数据的详细信息。
检查悬决的 PR 的质量并确保它们符合
样式指南 和
内容指南 要求。
首先查看最小的 PR(size/XS),然后逐渐扩展到最大的
PR(size/XXL),尽可能多地评审 PR。 确保贡献者完成 CLA 签署。
使用此脚本 自动提醒尚未签署
CLA 的贡献者签署 CLA。 针对提供提供反馈,请求其他 SIG 的成员进行技术审核。
为 PR 所建议的内容更改提供就地反馈。 如果您需要验证内容,请在 PR 上发表评论并要求贡献者提供更多细节。 设置相关的 sig/ 标签。 如果需要,从文件开头的 reviewers: 块中指派评阅人。 使用 /approve 评论来批准可以合并的 PR,在 PR 就绪时将其合并。
PR 在被合并之前,应该有来自其他成员的 /lgtm 评论。 可以考虑接受那些技术上准确,但文风上不满足
风格指南 要求的 PR。
可以登记一个新的 Issue 来解决文档风格问题,并将其标记为 good first issue。 对于管理人有用的 GitHub 查询 执行管理操作时,以下查询很有用。完成以下这些查询后,剩余的要审阅的 PR 列表通常很小。
这些查询都不包含本地化的 PR,并仅包含主分支上的 PR(除了最后一个查询)。
未签署 CLA,不可合并的 PR :
提醒贡献者签署 CLA。如果机器人和审阅者都已经提醒他们,请关闭 PR,并提醒他们在签署 CLA 后可以重新提交。
在作者没有签署 CLA 之前,不要审阅他们的 PR!
需要 LGTM :
列举需要来自成员的 LGTM 评论的 PR。
如果需要技术审查,请告知机器人所建议的审阅者。
如果 PR 继续改进,就地提供更改建议或反馈。
已有 LGTM标签,需要 Docs 团队批准 :
列举需要 /approve 评论来合并的 PR。
快速批阅 :
列举针对主分支的、没有明确合并障碍的 PR。
在浏览 PR 时,可以将 "XS" 尺寸标签更改为 "S"、"M"、"L"、"XL"、"XXL"。
非主分支的 PR :
如果 PR 针对 dev- 分支,则表示它适用于即将发布的版本。
请添加带有 /assign @<负责人的 github 账号>,将其指派给
发行版本负责人 。
如果 PR 是针对旧分支,请帮助 PR 作者确定是否所针对的是最合适的分支。
何时关闭 PR 审查和批准是缩短和更新我们的 PR 队列的一种方式;另一种方式是关闭 PR。
当以下条件满足时,可以关闭 PR:
不要害怕关闭 PR。贡献者可以轻松地重新打开并继续工作。
通常,关闭通知会激励作者继续完成其贡献。
要关闭 PR,请在 PR 上输入 /close 评论。
说明: 一个名为
fejta-bot 的自动服务会在 Issue 停滞 90
天后自动将其标记为过期;然后再等 30 天,如果仍然无人过问,则将其关闭。
PR 管理者应该在 issues 处于无人过问状态 14-30 天后关闭它们。
7.6 - 参考文档概述 本节的主题是描述如何生成 Kubernetes 参考指南。
要生成参考文档,请参考下面的指南:
7.6.1 - 为上游 Kubernetes 代码库做出贡献 此页面描述如何为上游 kubernetes/kubernetes 项目做出贡献,如修复 Kubernetes API
文档或 Kubernetes 组件(例如 kubeadm、kube-apiserver、kube-controller-manager 等)
中发现的错误。
如果您仅想从上游代码重新生成 Kubernetes API 或 kube-* 组件的参考文档。请参考以下说明:
准备开始 你必须设置 GOPATH 环境变量,并且 etcd 的位置必须在 PATH 环境变量中。 基本说明 Kubernetes API 和 kube-* 组件(例如 kube-apiserver、kube-controller-manager)的参考文档
是根据上游 Kubernetes 中的源代码自动生成的。
当您在生成的文档中看到错误时,您可能需要考虑创建一个 PR 用来在上游项目中对其进行修复。
克隆 Kubernetes 代码仓库 如果您还没有 kubernetes/kubernetes 代码仓库,请参照下列命令获取:
mkdir $GOPATH /src
cd $GOPATH /src
go get github.com/kubernetes/kubernetes
确定您的 kubernetes/kubernetes 代码仓库克隆的根目录。
例如,如果按照前面的步骤获取代码仓库,则你的根目录为 $GOPATH/src/github.com/kubernetes/kubernetes。
接下来其余步骤将你的根目录称为 <k8s-base>。
确定您的 kubernetes-sigs/reference-docs
代码仓库克隆的根目录。
例如,如果按照前面的步骤获取代码仓库,则你的根目录为
$GOPATH/src/github.com/kubernetes-sigs/reference-docs。
接下来其余步骤将你的根目录称为 <rdocs-base>。
编辑 Kubernetes 源代码 Kubernetes API 参考文档是根据 OpenAPI 规范自动生成的,该规范是从 Kubernetes 源代码生成的。
如果要更改 API 参考文档,第一步是更改 Kubernetes 源代码中的一个或多个注释。
kube-* 组件的文档也是从上游源代码生成的。您必须更改与要修复的组件相关的代码,才能修复生成的文档。
更改上游 Kubernetes 源代码 说明: 以下步骤仅作为示例,不是通用步骤,具体情况因环境而异。
以下在 Kubernetes 源代码中编辑注释的示例。
在您本地的 kubernetes/kubernetes 代码仓库中,检出 master 分支,并确保它是最新的:
cd <k8s-base>
git checkout master
git pull https://github.com/kubernetes/kubernetes master
假设 master 分支中的下面源文件中包含拼写错误 "atmost":
kubernetes/kubernetes/staging/src/k8s.io/api/apps/v1/types.go
在你的本地环境中,打开 types.go 文件,然后将 "atmost" 更改为 "at most"。
以下命令验证你已经更改了文件:
输出显示您在 master 分支上,types.go 源文件已被修改:
On branch master
...
modified: staging/src/k8s.io/api/apps/v1/types.go
提交已编辑的文件 运行 git add 和 git commit 命令提交到目前为止所做的更改。
在下一步中,您将进行第二次提交,将更改分成两个提交很重要。
生成 OpenAPI 规范和相关文件 进入 <k8s-base> 目录并运行以下脚本:
hack/update-generated-swagger-docs.sh
hack/update-openapi-spec.sh
hack/update-generated-protobuf.sh
hack/update-api-reference-docs.sh
运行 git status 命令查看生成的文件。
On branch master
...
modified: api/openapi-spec/swagger.json
modified: api/swagger-spec/apps_v1.json
modified: docs/api-reference/apps/v1/definitions.html
modified: staging/src/k8s.io/api/apps/v1/generated.proto
modified: staging/src/k8s.io/api/apps/v1/types.go
modified: staging/src/k8s.io/api/apps/v1/types_swagger_doc_generated.go
查看 api/openapi-spec/swagger.json 的内容,以确保拼写错误已经被修正。
例如,您可以运行 git diff -a api/openapi-spec/swagger.json 命令。
这很重要,因为 swagger.json 是文档生成过程中第二阶段的输入。
运行 git add 和 git commit 命令来提交您的更改。现在您有两个提交(commits):
一种包含编辑的 types.go 文件,另一种包含生成的 OpenAPI 规范和相关文件。
将这两个提交分开独立。也就是说,不要 squash 您的提交。
将您的更改作为 PR
提交到 kubernetes/kubernetes 代码仓库的 master 分支。
关注您的 PR,并根据需要回复 reviewer 的评论。继续关注您的 PR,直到 PR 被合并为止。
PR 57758 是修复 Kubernetes
源代码中的拼写错误的拉取请求的示例。
将你的提交 Cherrypick 到发布分支 在上一节中,你在 master 分支中编辑了一个文件,然后运行了脚本用来生成 OpenAPI 规范和相关文件。
然后用 PR 将你的更改提交到 kubernetes/kubernetes 代码仓库的 master 分支中。
现在,需要将你的更改反向移植到已经发布的分支。
例如,假设 master 分支被用来开发 Kubernetes 1.10 版,并且你想将更改反向移植到 release-1.9 分支。
回想一下,您的 PR 有两个提交:一个用于编辑 types.go,一个用于由脚本生成的文件。
下一步是将你的第一次提交 cherrypick 到 release-1.9 分支。这样做的原因是仅 cherrypick 编辑了 types.go 的提交,
而不是具有脚本运行结果的提交。
有关说明,请参见提出 Cherry Pick 。
说明: 提出 Cherry Pick 要求你有权在 PR 中设置标签和里程碑。如果您没有这些权限,
则需要与可以为你设置标签和里程碑的人员合作。
当你发起 PR 将你的一个提交 cherry pick 到 release-1.9 分支中时,下一步是在本地环境的 release-1.9
分支中运行如下脚本。
hack/update-generated-swagger-docs.sh
hack/update-openapi-spec.sh
hack/update-generated-protobuf.sh
hack/update-api-reference-docs.sh
现在将提交添加到您的 Cherry-Pick PR 中,该 PR 中包含最新生成的 OpenAPI 规范和相关文件。
关注你的 PR,直到其合并到 release-1.9 分支中为止。
此时,master 分支和 release-1.9 分支都具有更新的 types.go 文件和一组生成的文件,
这些文件反映了对 types.go 所做的更改。
请注意,生成的 OpenAPI 规范和其他 release-1.9 分支中生成的文件不一定与 master 分支中生成的文件相同。
release-1.9 分支中生成的文件仅包含来自 Kubernetes 1.9 的 API 元素。
master 分支中生成的文件可能包含不在 1.9 中但正在为 1.10 开发的 API 元素。
生成已发布的参考文档 上一节显示了如何编辑源文件然后生成多个文件,包括在 kubernetes/kubernetes 代码仓库中的
api/openapi-spec/swagger.json。swagger.json 文件是 OpenAPI 定义文件,可用于生成 API 参考文档。
现在,您可以按照
生成 Kubernetes API 的参考文档
指南来生成
已发布的 Kubernetes API 参考文档 。
接下来 7.6.2 - 快速入门 本页讨论如何使用 update-imported-docs 脚本来生成 Kubernetes 参考文档。
此脚本将构建的配置过程自动化,并为某个发行版本生成参考文档。
准备开始 需求 你需要一台 Linux 或 macOS 机器。
你需要安装以下工具:
获取文档仓库 确保你的 website 派生仓库与 kubernetes/website 主分支一致,并克隆
你的派生仓库。
mkdir github.com
cd github.com
git clone git@github.com:<your_github_username>/website.git
确定你的克隆副本的根目录。例如,如果你按照前面的步骤获取了仓库,你的根目录
会是 github.com/website。接下来的步骤中,<web-base> 用来指代你的根目录。
说明: 如果你希望更改构建工具和 API 参考资料,可以阅读
上游贡献指南 .
update-imported-docs 的概述 脚本 update-imported-docs 位于 <web-base>/update-imported-docs/ 目录下,
能够生成以下参考文档:
Kubernetes 组件和工具的参考页面 kubectl 命令参考文档Kubernetes API 参考文档 脚本 update-imported-docs 基于 Kubernetes 源代码生成参考文档。
过程中会在你的机器的 /tmp 目录下创建临时目录,克隆所需要的仓库
kubernetes/kubernetes 和 kubernetes-sigs/reference-docs 到此临时目录。
脚本会将 GOPATH 环境变量设置为指向此临时目录。
此外,脚本会设置三个环境变量:
K8S_RELEASEK8S_ROOTK8S_WEBROOT脚本需要两个参数才能成功运行:
一个 YAML 配置文件(reference.yml) 一个发行版本字符串,例如:1.17 配置文件中包含 generate-command 字段,其中定义了一系列来自于
kubernetes-sigs/reference-docs/Makefile 的构建指令。
变量 K8S_RELEASE 用来确定所针对的发行版本。
脚本 update-imported-docs 执行以下步骤:
克隆配置文件中所指定的相关仓库。就生成参考文档这一目的而言,要克隆的
仓库默认为 kubernetes-sigs/reference-docs。 在所克隆的仓库下运行命令,准备文档生成器,之后生成 HTML 和 Markdown 文件。 将所生成的 HTML 和 Markdown 文件复制到 <web-base> 本地克隆副本中,
放在配置文件中所指定的目录下。 更新 kubectl.md 文件中对 kubectl 命令文档的链接,使之指向 kubectl
命令参考中对应的节区。 当所生成的文件已经被放到 <web-base> 目录下,你就可以将其提交到你的派生副本中,
并基于所作提交发起拉取请求(PR) 到 k/website 仓库。
每个配置文件可以包含多个被导入的仓库。当必要时,你可以通过手工编辑此文件进行定制。
你也可以通过创建新的配置文件来导入其他文档集合。
下面是 YAML 配置文件的一个例子:
repos :
- name : community
remote : https://github.com/kubernetes/community.git
branch : master
files :
- src : contributors/devel/README.md
dst : docs/imported/community/devel.md
- src : contributors/guide/README.md
dst : docs/imported/community/guide.md
通过工具导入的单页面的 Markdown 文档必须遵从
文档样式指南 。
定制 reference.yml 打开 <web-base>/update-imported-docs/reference.yml 文件进行编辑。
在不了解参考文档构造命令的情况下,不要更改 generate-command 字段的内容。
你一般不需要更新 reference.yml 文件。不过也有时候上游的源代码发生变化,
导致需要对配置文件进行更改(例如:Golang 版本依赖或者第三方库发生变化)。
如果你遇到类似问题,请在 Kubernetes Slack 的 #sig-docs 频道
联系 SIG-Docs 团队。
说明: 注意,generate-command 是一个可选项,用来运行指定命令或者短脚本以在仓库
内生成文档。
在 reference.yml 文件中,files 属性包含了一组 src 和 dst 字段。
src 字段给出在所克隆的 kubernetes-sigs/reference-docs 构造目录中生成的
Markdown 文件的位置,而 dst 字段则给出了对应文件要复制到的、所克隆的
kubernetes/website 仓库中的位置。例如:
repos :
- name : reference-docs
remote : https://github.com/kubernetes-sigs/reference-docs.git
files :
- src : gen-compdocs/build/kube-apiserver.md
dst : content/en/docs/reference/command-line-tools-reference/kube-apiserver.md
...
注意,如果从同一源目录中有很多文件要复制到目标目录,你可以在为 src 所设置的
值中使用通配符。这时,为 dst 所设置的值必须是目录名称。例如:
files :
- src : gen-compdocs/build/kubeadm*.md
dst : content/en/docs/reference/setup-tools/kubeadm/generated/
运行 update-imported-docs 工具 你可以用如下方式运行 update-imported-docs 工具:
cd <web-base>/update-imported-docs
./update-imported-docs <configuration-file.yml> <release-version>
例如:
./update-imported-docs reference.yml 1.17
修复链接 配置文件 release.yml 中包含用来修复相对链接的指令。
若要修复导入文件中的相对链接,将 gen-absolute-links 属性设置为 true。
你可以在 release.yml
文件中找到示例。
添加并提交 kubernetes/website 中的变更 枚举新生成并复制到 <web-base> 的文件:
输出显示新生成和已修改的文件。取决于上游源代码的修改多少,
所生成的输出也会不同。
生成的 Kubernetes 组件文档 content/en/docs/reference/command-line-tools-reference/cloud-controller-manager.md
content/en/docs/reference/command-line-tools-reference/kube-apiserver.md
content/en/docs/reference/command-line-tools-reference/kube-controller-manager.md
content/en/docs/reference/command-line-tools-reference/kube-proxy.md
content/en/docs/reference/command-line-tools-reference/kube-scheduler.md
content/en/docs/reference/setup-tools/kubeadm/generated/kubeadm.md
content/en/docs/reference/kubectl/kubectl.md
生成的 kubectl 命令参考文件 static/docs/reference/generated/kubectl/kubectl-commands.html
static/docs/reference/generated/kubectl/navData.js
static/docs/reference/generated/kubectl/scroll.js
static/docs/reference/generated/kubectl/stylesheet.css
static/docs/reference/generated/kubectl/tabvisibility.js
static/docs/reference/generated/kubectl/node_modules/bootstrap/dist/css/bootstrap.min.css
static/docs/reference/generated/kubectl/node_modules/highlight.js/styles/default.css
static/docs/reference/generated/kubectl/node_modules/jquery.scrollto/jquery.scrollTo.min.js
static/docs/reference/generated/kubectl/node_modules/jquery/dist/jquery.min.js
static/docs/reference/generated/kubectl/css/font-awesome.min.css
生成的 Kubernetes API 参考目录与文件 static/docs/reference/generated/kubernetes-api/v1.20/index.html
static/docs/reference/generated/kubernetes-api/v1.20/js/navData.js
static/docs/reference/generated/kubernetes-api/v1.20/js/scroll.js
static/docs/reference/generated/kubernetes-api/v1.20/js/query.scrollTo.min.js
static/docs/reference/generated/kubernetes-api/v1.20/css/font-awesome.min.css
static/docs/reference/generated/kubernetes-api/v1.20/css/bootstrap.min.css
static/docs/reference/generated/kubernetes-api/v1.20/css/stylesheet.css
static/docs/reference/generated/kubernetes-api/v1.20/fonts/FontAwesome.otf
static/docs/reference/generated/kubernetes-api/v1.20/fonts/fontawesome-webfont.eot
static/docs/reference/generated/kubernetes-api/v1.20/fonts/fontawesome-webfont.svg
static/docs/reference/generated/kubernetes-api/v1.20/fonts/fontawesome-webfont.ttf
static/docs/reference/generated/kubernetes-api/v1.20/fonts/fontawesome-webfont.woff
static/docs/reference/generated/kubernetes-api/v1.20/fonts/fontawesome-webfont.woff2
运行 git add 和 git commit 提交文件。
创建拉取请求 接下来创建一个对 kubernetes/website 仓库的拉取请求(PR)。
监视所创建的 PR,并根据需要对评阅意见给出反馈。
继续监视该 PR 直到其被合并为止。
当你的 PR 被合并几分钟之后,你所做的对参考文档的变更就会出现
发布的文档 上。
接下来 要手动设置所需的构造仓库,执行构建目标,以生成各个参考文档,可参考下面的指南:
7.6.3 - 为 Kubernetes API 生成参考文档 本页面展示了如何为 Kubernetes API 更新自动生成的参考文档。
Kubernetes API 参考文档是从
Kubernetes OpenAPI 规范
构建的,而工具是从
kubernetes-sigs/reference-docs 构建的。
如果您在生成的文档中发现错误,则需要在上游修复 。
如果您只需要从 OpenAPI 规范中重新生成参考文档,请继续阅读此页。
准备开始 需求 你需要一台 Linux 或 macOS 机器。
你需要安装以下工具:
配置本地仓库 创建本地工作区并设置你的 GOPATH。
mkdir -p $HOME /<workspace>
export GOPATH = $HOME /<workspace>
获取以下仓库的本地克隆:
go get -u github.com/kubernetes-incubator/reference-docs
go get -u github.com/go-openapi/loads
go get -u github.com/go-openapi/spec
如果你还没有下载过 kubernetes/website 仓库,现在下载:
git clone https://github.com/<your-username>/website $GOPATH /src/github.com/<your-username>/website
克隆 kubernetes/kubernetes 仓库作为 k8s.io/kubernetes:
git clone https://github.com/kubernetes/kubernetes $GOPATH /src/k8s.io/kubernetes
生成 API 参考文档 本节说明如何生成已发布的 Kubernetes API 参考文档 。
设置构建变量 设置 K8S_ROOT 为 <k8s-base>. 设置 K8S_WEBROOT 为 <web-base>. 设置 K8S_RELEASE 为要构建的文档的版本。
例如,如果您想为 Kubernetes 1.17 构建文档,请将 K8S_RELEASE 设置为 1.17。 例如:
export K8S_WEBROOT=$(GOPATH)/src/github.com/<your-username>/website
export K8S_ROOT=$(GOPATH)/src/k8s.io/kubernetes
export K8S_RELEASE=1.17
创建版本目录并复制 OpenAPI 规范 构建目标 updateapispec 负责创建版本化的构建目录。
目录创建了之后,从 <k8s-base> 仓库取回 OpenAPI 规范文件。
这些步骤确保配置文件的版本和 Kubernetes OpenAPI 规范的版本与发行版本匹配。
版本化目录的名称形式为 v<major>_<minor>。
在 '' 目录中,运行以下命令来构建:
cd <rdocs-base>
make updateapispec
构建 API 参考文档 构建目标 copyapi 会生成 API 参考文档并将所生成文件复制到
<web-base 中的目录下。
在 <rdocs-base> 目录中运行以下命令:
cd <rdocs-base>
make copyapi
验证是否已生成这两个文件:
[ -e "<rdocs-base>/gen-apidocs/generators/build/index.html" ] && echo "index.html built" || echo "no index.html"
[ -e "<rdocs-base>/gen-apidocs/generators/build/navData.js" ] && echo "navData.js built" || echo "no navData.js"
进入本地 <web-base> 目录,检查哪些文件被更改:
输出类似于:
static/docs/reference/generated/kubernetes-api/v1.20/css/bootstrap.min.css
static/docs/reference/generated/kubernetes-api/v1.20/css/font-awesome.min.css
static/docs/reference/generated/kubernetes-api/v1.20/css/stylesheet.css
static/docs/reference/generated/kubernetes-api/v1.20/fonts/FontAwesome.otf
static/docs/reference/generated/kubernetes-api/v1.20/fonts/fontawesome-webfont.eot
static/docs/reference/generated/kubernetes-api/v1.20/fonts/fontawesome-webfont.svg
static/docs/reference/generated/kubernetes-api/v1.20/fonts/fontawesome-webfont.ttf
static/docs/reference/generated/kubernetes-api/v1.20/fonts/fontawesome-webfont.woff
static/docs/reference/generated/kubernetes-api/v1.20/fonts/fontawesome-webfont.woff2
static/docs/reference/generated/kubernetes-api/v1.20/index.html
static/docs/reference/generated/kubernetes-api/v1.20/js/jquery.scrollTo.min.js
static/docs/reference/generated/kubernetes-api/v1.20/js/navData.js
static/docs/reference/generated/kubernetes-api/v1.20/js/scroll.js
更新 API 参考索引页面 在为新发行版本生成参考文档时,需要更新下面的文件,使之包含新的版本号:
<web-base>/content/en/docs/reference/kubernetes-api/api-index.md。
打开编辑 <web-base>/content/en/docs/reference/_index.md,添加指向最新 API 参考
的链接,删除最老的 API 版本。
通常保留最近的五个版本的 API 参考的链接。 在本地测试 API 参考 发布 API 参考的本地版本。
检查本地预览 。
cd <web-base>
git submodule update --init --recursive --depth 1 # if not already done
make container-serve
提交更改 在 <web-base> 中运行 git add 和 git commit 来提交更改。
基于你所生成的更改创建 PR ,
提交到 kubernetes/website 仓库。
监视您提交的 PR,并根据需要回复 reviewer 的评论。继续监视您的 PR,直到合并为止。
接下来 7.6.4 - 为 kubectl 命令集生成参考文档 本页面描述了如何生成 kubectl 命令参考。
准备开始 需求 你需要一台 Linux 或 macOS 机器。
你需要安装以下工具:
配置本地仓库 创建本地工作区并设置你的 GOPATH。
mkdir -p $HOME /<workspace>
export GOPATH = $HOME /<workspace>
获取以下仓库的本地克隆:
go get -u github.com/spf13/pflag
go get -u github.com/spf13/cobra
go get -u gopkg.in/yaml.v2
go get -u kubernetes-incubator/reference-docs
如果您还没有获取过 kubernetes/website 仓库,现在获取之:
git clone https://github.com/<your-username>/website $GOPATH /src/github.com/<your-username>/website
克隆 kubernetes/kubernetes 仓库作为 k8s.io/kubernetes:
git clone https://github.com/kubernetes/kubernetes $GOPATH /src/k8s.io/kubernetes
从 $GOPATH/src/k8s.io/kubernetes/vendor/github.com 中移除 spf13 软件包。
rm -rf $GOPATH /src/k8s.io/kubernetes/vendor/github.com/spf13
kubernetes/kubernetes 仓库提供对 kubectl 和 kustomize 源代码的访问。
确定 kubernetes/kubernetes 仓库的本地主目录。
例如,如果按照前面的步骤来获取该仓库,则主目录是 $GOPATH/src/k8s.io/kubernetes.。
下文将该目录称为 <k8s-base>。 确定 kubernetes/website 仓库的本地主目录。
例如,如果按照前面的步骤来获取该仓库,则主目录是 $GOPATH/src/github.com/<your-username>/website。
下文将该目录称为 <web-base>。 在本地的 k8s.io/kubernetes 仓库中,检出感兴趣的分支并确保它是最新的。例如,
如果你想要生成 Kubernetes 1.17 的文档,可以使用以下命令:
cd <k8s-base>
git checkout v1.17.0
git pull https://github.com/kubernetes/kubernetes v1.17.0
如果不需要编辑 kubectl
源码,请按照说明配置构建变量 。
编辑 kubectl 源码 kubectl 命令的参考文档是基于 kubectl 源码自动生成的。如果想要修改参考文档,可以从修改
kubectl 源码中的一个或多个注释开始。在本地 kubernetes/kubernetes 仓库中进行修改,然后向
github.com/kubernetes/kubernetes 的 master
分支提交 PR。
PR 56673 是一个对 kubectl
源码中的笔误进行修复的 PR 示例。
跟踪你的 PR,并回应评审人的评论。继续跟踪你的 PR,直到它合入到 kubernetes/kubernetes 仓库的 master 分支中。
以 cherry-pick 方式将你的修改合入已发布分支 你的修改已合入 master 分支中,该分支用于开发下一个 Kubernetes 版本。
如果你希望修改部分出现在已发布的 Kubernetes 版本文档中,则需要提议将它们以
cherry-pick 方式合入已发布分支。
例如,假设 master 分支正用于开发 Kubernetes 1.16 版本,而你希望将修改合入到已发布的 1.15 版本分支。
相关的操作指南,请参见
提议一个 cherry-pick 。
跟踪你的 cherry-pick PR,直到它合入到已发布分支中。
说明: 提议一个 cherry-pick 需要你有在 PR 中设置标签和里程碑的权限。
如果你没有,你需要与有权限为你设置标签和里程碑的人合作完成。
设置构建变量 进入 <rdocs-base> 目录, 打开 Makefile 进行编辑:
设置 K8S_ROOT 为 <k8s-base>。 设置 K8S_WEBROOT 为 <web-base>。 设置 K8S_RELEASE 为要构建文档的版本。
例如,如果您想为 Kubernetes 1.17 构建文档,请将 K8S_RELEASE 设置为 1.17。 例如:
export K8S_WEBROOT=$(GOPATH)/src/github.com/<your-username>/website
export K8S_ROOT=$(GOPATH)/src/k8s.io/kubernetes
export K8S_RELEASE=1.17
创建版本目录 构建目标 createversiondirs 会生成一个版本目录并将 kubectl 参考配置文件复制到该目录中。
版本目录的名字模式为 v<major>_<minor>。
在 <rdocs-base> 目录下,执行下面的命令:
cd <rdocs-base>
make createversiondirs
从 kubernetes/kubernetes 检出一个分支 在本地 <k8s-base> 仓库中,检出你想要生成文档的、包含 Kubernetes 版本的分支。
例如,如果希望为 Kubernetes 1.17 版本生成文档,请检出 v1.17.0 标记。
确保本地分支是最新的。
cd <k8s-base>
git checkout v1.17.0
git pull https://github.com/kubernetes/kubernetes v1.17.0
运行文档生成代码 在本地的 <rdocs-base> 目录下,运行 copycli 构建目标。此命令以 root 账号运行:
cd <rdocs-base>
make copycli
copycli 命令将清理暂存目录,生成 kubectl 命令文件,并将整理后的 kubectl 参考 HTML 页面和
文件复制到 <web-base>。
找到生成的文件 验证是否已生成以下两个文件:
[ -e "<rdocs-base>/gen-kubectldocs/generators/build/index.html" ] && echo "index.html built" || echo "no index.html"
[ -e "<rdocs-base>/gen-kubectldocs/generators/build/navData.js" ] && echo "navData.js built" || echo "no navData.js"
找到复制的文件 确认所有生成的文件都已复制到你的 <web-base>:
输出应包括修改后的文件:
static/docs/reference/generated/kubectl/kubectl-commands.html
static/docs/reference/generated/kubectl/navData.js
此外,输出可能还包含:
static/docs/reference/generated/kubectl/scroll.js
static/docs/reference/generated/kubectl/stylesheet.css
static/docs/reference/generated/kubectl/tabvisibility.js
static/docs/reference/generated/kubectl/node_modules/bootstrap/dist/css/bootstrap.min.css
static/docs/reference/generated/kubectl/node_modules/highlight.js/styles/default.css
static/docs/reference/generated/kubectl/node_modules/jquery.scrollto/jquery.scrollTo.min.js
static/docs/reference/generated/kubectl/node_modules/jquery/dist/jquery.min.js
static/docs/reference/generated/kubectl/node_modules/font-awesome/css/font-awesome.min.css
在本地测试文档 在本地 <web-base> 中构建 Kubernetes 文档。
cd <web-base>
git submodule update --init --recursive --depth 1 # if not already done
make container-serve
查看本地预览 。
在 kubernetes/website 中添加和提交更改 运行 git add 和 git commit 提交修改文件。
创建 PR 对 kubernetes/website 仓库创建 PR。跟踪你的 PR,并根据需要回应评审人的评论。
继续跟踪你的 PR,直到它被合入。
在 PR 合入的几分钟后,你更新的参考主题将出现在已发布文档 中。
接下来 7.6.5 - 为 Kubernetes 组件和工具生成参考文档 本页面描述如何构造 Kubernetes 组件和工具的参考文档。
准备开始 阅读参考文档快速入门指南中的准备工作 节。
按照参考文档快速入门
指引,生成 Kubernetes 组件和工具的参考文档。
接下来 7.6.6 - 需求 你需要一台 Linux 或 macOS 机器。
你需要安装以下工具:
7.7 - 文档样式概述 本节的主题是提供有关写作风格、内容格式和组织以及如何使用
特定于 Kubernetes 文档的 Hugo 定制代码的指导。
7.7.1 - 文档内容指南 本页包含 Kubernetes 文档的一些指南。
如果你不清楚哪些事情是可以做的,请加入到
Kubernetes Slack 的 #sig-docs 频道提问!
你可以在 http://slack.k8s.io 注册到 Kubernetes Slack。
关于为 Kubernetes 文档创建新内容的更多信息,可参考
样式指南 。
概述 Kubernetes 网站(包括其文档)源代码位于
kubernetes/website 仓库中。
在 kubernetes/website/content/<语言代码>/docs 目录下, 绝大多数 Kubernetes
文档都是特定于 Kubernetes 项目 的。
可以发布的内容 只有当以下条件满足时,Kubernetes 文档才允许第三方项目的内容:
内容所描述的软件在 Kubernetes 项目内 内容所描述的软件不在 Kubernetes 项目内,却是让 Kubernetes 正常工作所必需的 内容是被 kubernetes.io 域名收编的,或者是其他位置的标准典型内容 第三方内容 Kubernetes 文档包含 Kubernetes 项目下的多个项目的应用示例。
这里的 Kubernetes 项目指的是 kubernetes 和
kubernetes-sigs GitHub 组织
下的项目。
链接到 Kubernetes 项目中活跃的内容是一直允许的。
Kubernetes 需要某些第三方内容才能正常工作。例如
容器运行时(containerd、CRI-O、Docker),
联网策略
(CNI 插件),Ingress 控制器
以及日志 等。
只有对应的第三方开源软件(OSS)是运行 Kubernetes 所必需的,才可以在文档中包含
指向这些 Kubernetes 项目之外的软件的链接。
双重来源的内容 只要有可能,Kubernetes 文档应该指向标准典型的信息源而不是直接托管多重来源的内容。
双重来源的内容需要双倍(甚至更多)的投入才能维护,而且通常很快就会变得停滞不前。
说明: 如果你是一个 Kubernetes 项目的维护者,需要帮忙托管你的文档,
请在 Kubernetes 的
#sig-docs 频道
提出请求。
如果你对允许出现的内容有疑问,请加入到 Kubernetes Slack
的 #sig-docs 频道提问!
接下来 7.7.2 - 文档样式指南 本页讨论 Kubernetes 文档的样式指南。
这些仅仅是指南而不是规则。
你可以自行决定,且欢迎使用 PR 来为此文档提供修改意见。
关于为 Kubernetes 文档贡献新内容的更多信息,可以参考
文档内容指南 。
样式指南的变更是 SIG Docs 团队集体决定。
如要提议更改或新增条目,请先将其添加到下一次 SIG Docs 例会的
议程表
上,并按时参加会议讨论。
语言 Kubernetes 文档已经被翻译为多个语种
(参见 本地化 READMEs )。
为文档提供一种新的语言翻译的途径可以在
本地化 Kubernetes 文档 中找到。
英语文档使用美国英语的拼写和语法。
对 API 对象使用大写驼峰式命名法 当你与指定的 API 对象进行交互时,使用 大写驼峰式命名法 ,
也被称为帕斯卡拼写法.
通常在讨论 API 对象时,使用
句子式大写 .
不要将 API 对象的名称切分成多个单词。例如,使用 PodTemplateList,不要
使用 Pod Template List。
引用 API 对象时不必强调 “object(对象)”,除非省略“object(object)”
会使得文字读起来很别扭。
关于 API 对象的约定 可以 不可以 Pod 有两个容器 pod 中有两个容器 此 HorizontalPodAutoscaler 负责... 此 HorizontalPodAutoscaler 对象负责 ... PodList 是 Pod 的列表 Pod List 是 pods 的列表 这两个 ContainerPorts ... 这两个 ContainerPort 对象 ... 这两个 ContainerStateTerminated 对象 ... 这两个 ContainerStateTerminateds ...
在占位符中使用尖括号 在占位符中使用尖括号,并让读者知道其中代表的事物。例如:
显示 Pod 信息:
kubectl describe pod <pod-名称> -n <名字空间>
如果名字空间被忽略,默认为 default,你可以忽略 '-n' 参数。
用粗体字表现用户界面元素 粗体界面元素约定 可以 不可以 点击 Fork . 点击 "Fork". 选择 Other . 选择 "Other".
定义或引入新术语时使用斜体 新术语约定 可以 不可以 每个 集群 是一组节点 ... 每个“集群”是一组节点 ... 这些组件构成了 控制面 . 这些组件构成了 控制面 .
使用代码样式表现文件名、目录和路径 文件名、目录和路径约定 可以 不可以 打开 envars.yaml 文件 打开 envars.yaml 文件 进入到 /docs/tutorials 目录 进入到 /docs/tutorials 目录 打开 /_data/concepts.yaml 文件 打开 /_data/concepts.yaml 文件
在引号内使用国际标准标点 标点符号约定 可以 不可以 事件记录中都包含对应的“stage”。 事件记录中都包含对应的“stage。” 此副本称作一个“fork”。 此副本称作一个“fork。”
为行间代码、命令与 API 对象使用代码样式 对于 HTML 文档中的行间代码,使用 <code> 标记。
在 Markdown 文档中,使用反引号(`)。
行间代码和命令约定 可以 不可以 kubectl run 命令会创建一个 Pod"kubectl run" 命令会创建一个 pod。 每个节点上的 kubelet 都会获得一个 Lease 每个节点上的 kubelet 都会获得一个 lease… 一个 PersistentVolume 代表持久存储 一个 Persistent Volume 代表持久存储… 在声明式管理中,使用 kubectl apply。 在声明式管理中,使用 "kubectl apply"。 用三个反引号来(```)标示代码示例 用其他语法来标示代码示例。 使用单个反引号来标示行间代码。例如:var example = true。 使用两个星号(**)或者一个下划线(_)来标示行间代码。例如:var example = true 。 在多行代码块之前和之后使用三个反引号标示隔离的代码块。 使用多行代码块来创建示意图、流程图或者其他表示。 使用符合上下文的有意义的变量名。 使用诸如 'foo'、'bar' 和 'baz' 这类无意义且无语境的变量名。 删除代码中行尾空白。 在代码中包含行尾空白,因为屏幕抓取工具通常也会抓取空白字符。
说明: 网站支持为代码示例使用语法加亮,不过指定语法加亮是可选的。
代码段的语法加亮要遵从
对比度指南 为对象字段名和名字空间使用代码风格 对象字段名约定 可以 不可以 在配置文件中设置 replicas 字段的值。 在配置文件中设置 "replicas" 字段的值。 exec 字段的值是一个 ExecAction 对象。"exec" 字段的值是一个 ExecAction 对象。 在 kube-system 名字空间中以 DaemonSet 形式运行此进程。 在 kube-system 名字空间中以 DaemonSet 形式运行此进程。
用代码样式书写 Kubernetes 命令工具和组件名 Kubernetes 命令工具和组件名 可以 不可以 kubelet 维持节点稳定性。kubelet 负责维护节点稳定性。 kubectl 处理 API 服务器的定位和身份认证。kubectl 处理 API 服务器的定位和身份认证。 使用该证书运行进程 kube-apiserver --client-ca-file=FILENAME. 使用证书运行进程 kube-apiserver --client-ca-file=FILENAME.
用工具或组件名称开始一句话 工具或组件名称使用约定 可以 不可以 The kubeadm tool bootstraps and provisions machines in a cluster. kubeadm tool bootstraps and provisions machines in a cluster.The kube-scheduler is the default scheduler for Kubernetes. kube-scheduler is the default scheduler for Kubernetes.
尽量使用通用描述而不是组件名称 组件名称与通用描述 可以 不可以 Kubernetes API 服务器提供 OpenAPI 规范。 apiserver 提供 OpenAPI 规范 聚合 APIs 是下级 API 服务器。 聚合 APIs 是下级 APIServers。
使用普通样式表达字符串和整数字段值 对于字符串或整数,使用正常样式,不要带引号。
字符串和整数字段值约定 可以 不可以 将 imagePullPolicy 设置为 Always。 将 imagePullPolicy 设置为 "Always"。 将 image 设置为 nginx:1.16. 将 image 设置为 nginx:1.16。 将 replicas 字段值设置为 2. 将 replicas 字段值设置为 2.
代码段格式 不要包含命令行提示符 命令行提示符约定 可以 不可以 kubectl get pods $ kubectl get pods
将命令和输出分开 例如:
验证 Pod 已经在你所选的节点上运行:
kubectl get pods --output=wide
输出类似于:
NAME READY STATUS RESTARTS AGE IP NODE
nginx 1/1 Running 0 13s 10.200.0.4 worker0
为 Kubernetes 示例给出版本 代码示例或者配置示例如果包含版本信息,应该与对应的文字描述一致。
如果所给的信息是特定于具体版本的,需要在
任务模版
或教程模版
的 prerequisites 小节定义 Kubernetes 版本。
页面保存之后,prerequisites 小节会显示为 开始之前 。
如果要为任务或教程页面指定 Kubernetes 版本,可以在文件的前言部分包含
min-kubernetes-server-version 信息。
如果示例 YAML 是一个独立文件,找到并审查包含该文件的主题页面。
确认使用该独立 YAML 文件的主题都定义了合适的版本信息。
如果独立的 YAML 文件没有在任何主题中引用,可以考虑删除该文件,
而不是继续更新它。
例如,如果你在编写一个教程,与 Kubernetes 1.8 版本相关。那么你的 Markdown
文件的文件头应该开始起来像这样:
---
title : <教程标题>
min-kubernetes-server-version : v1.8
---
在代码和配置示例中,不要包含其他版本的注释信息。
尤其要小心不要在示例中包含不正确的注释信息,例如:
apiVersion : v1 # 早期版本使用...
kind : Pod
...
Kubernetes.io 术语列表 以下特定于 Kubernetes 的术语和词汇在使用时要保持一致性。
Kubernetes.io 词汇表 术语 用法 Kubernetes Kubernetes 的首字母要保持大写。 Docker Docker 的首字母要保持大写。 SIG Docs SIG Docs 是正确拼写形式,不要用 SIG-DOCS 或其他变体。 On-premises On-premises 或 On-prem 而不是 On-premise 或其他变体。
短代码(Shortcodes) Hugo 短代码(Shortcodes)
有助于创建比较漂亮的展示效果。我们的文档支持三个不同的这类短代码。
注意 {{< note >}}、小心 {{< caution >}} 和 警告 {{< warning >}}。
将要突出显示的文字用短代码的开始和结束形式包围。
使用下面的语法来应用某种样式:
{{< note >}}
不需要前缀;短代码会自动添加前缀(注意:、小心:等)
{{< /note >}}
输出的样子是:
说明: 你所选择的标记决定了文字的前缀。
注释(Note) 使用短代码 {{< note >}} 来突出显示某种提示或者有助于读者的信息。
例如:
{{< note >}}
在这类短代码中仍然 _可以_ 使用 Markdown 语法。
{{< /note >}}
输出为:
说明: 在这类短代码中仍然 可以 使用 Markdown 语法。
你可以在列表中使用 {{< note >}}:
1. 在列表中使用 note 短代码
1. 带嵌套 note 的第二个条目
{{< note >}}
警告、小心和注意短代码可以嵌套在列表中,但是要缩进四个空格。
参见[常见短代码问题](#common-shortcode-issues)。
{{< /note >}}
1. 列表中第三个条目
1. 列表中第四个条目
其输出为:
在列表中使用 note 短代码
带嵌套 note 的第二个条目
说明: 警告、小心和注意短代码可以嵌套在列表中,但是要缩进四个空格。
参见
常见短代码问题 。
列表中第三个条目
列表中第四个条目
小心(Caution) 使用 {{< caution >}} 短代码来引起读者对某段信息的重视,以避免遇到问题。
例如:
{{< caution >}}
此短代码样式仅对标记之上的一行起作用。
{{< /caution >}}
其输出为:
注意: 此短代码样式仅对标记之上的一行起作用。
警告(Warning) 使用 {{< warning >}} 来表明危险或者必须要重视的一则信息。
例如:
{{< warning >}}
注意事项
{{< /warning >}}
其输出为:
警告: 注意事项
Katacoda 嵌套现场环境 此按钮允许用户使用 Katacoda 终端
在其浏览器中运行 Minikube。该环境降低了用户对 Minikube 的入门难度,
只需要一次鼠标点击即可完成,而不需要完全经历 Minikube 和 kubectl 的安装过程。
嵌套现场环境配置为运行 minikube start,允许用户在文档所在的窗口完成教程。
注意: 会话限制为 15 分钟。
例如:
{{< kat-button >}}
其输出为:
Launch Terminal 常见的短代码问题 编号列表 短代码会打乱编号列表的编号,除非你在信息和标志之前都缩进四个空格。
例如:
1. 预热到 350˚F
1. 准备好面糊,倒入烘烤盘
{{< note >}}给盘子抹上油可以达到最佳效果。{{< /note >}}
1. 烘烤 20 到 25 分钟,或者直到满意为止。
其输出结果为:
预热到 350˚F 准备好面糊,倒入烘烤盘说明: 给盘子抹上油可以达到最佳效果。
烘烤 20 到 25 分钟,或者直到满意为止。 Include 语句 如果短代码出现在 include 语境中,会导致网站无法构建。
你必须将他们插入到上级文档中,分别将开始标记和结束标记插入到 include 语句之前和之后。
例如:
{{< note >}}
{{< include "task-tutorial-prereqs.md" >}}
{{< /note >}}
Markdown 元素 换行 使用单一换行符来隔离块级内容,例如标题、列表、图片、代码块以及其他元素。
这里的例外是二级标题,必须有两个换行符。
二级标题紧随一级标题(或标题),中间没有段落或文字。
两行的留白有助于在代码编辑器中查看整个内容的结构组织。
标题 访问文档的读者可能会使用屏幕抓取程序或者其他辅助技术。
屏幕抓取器 是一种线性输出设备,
它们每次输出页面上的一个条目。
如果页面上内容过多,你可以使用标题来为页面组织结构。
页面的良好结构对所有读者都有帮助,使得他们更容易浏览或者过滤感兴趣的内容。
标题约定 可以 不可以 更新页面或博客在前言部分中的标题 使用一级标题。因为 Hugo 会自动将页面前言部分的标题转化为一级标题。 使用编号的标题以便内容组织有一个更有意义的结构。 使用四级到六级标题,除非非常有必要这样。如果你要编写的内容有非常多细节,可以尝试拆分成多个不同页面。 在非博客内容页面中使用井号(#) 使用下划线 --- 或 === 来标记一级标题。 使用正常大小写来标示标题。例如:Extend kubectl with plugins 使用首字母大写来标示标题。例如:Extend Kubectl With Plugins
段落 段落约定 可以 不可以 尝试不要让段落超出 6 句话。 用空格来缩进第一段。例如,⋅⋅⋅段落前面的三个空格会将其缩进。 使用三个连字符(---)来创建水平线。使用水平线来分隔段落内容。例如,在故事中切换场景或者在上下文中切换主题。 使用水平线来装饰页面。
链接 链接约定 可以 不可以 插入超级链接时给出它们所链接到的目标内容的上下文。例如:你的机器上某些端口处于开放状态。参见检查所需端口 了解更详细信息。 使用有二义性的术语,如“点击这里”。例如:你的机器上某些端口处于打开状态。参见这里 了解详细信息。 编写 Markdown 风格的链接:[链接文本](URL)。例如:[Hugo 短代码](/zh/docs/contribute/style/hugo-shortcodes/#table-captions),输出是Hugo 短代码 . 编写 HTML 风格的超级链接:<a href="/media/examples/link-element-example.css" target="_blank">访问我们的教程!</a>,或者创建会打开新 Tab 页或新窗口的链接。例如:[网站示例](https://example.com){target="_blank"}。
列表 将一组相互关联的内容组织到一个列表中,以便表达这些条目彼此之间有先后顺序或者某种相互关联关系。
当屏幕抓取器遇到列表时,无论该列表是否有序,它会告知用户存在一组枚举的条目。
用户可以使用箭头键来上下移动,浏览列表中条目。
网站导航链接也可以标记成列表条目,因为说到底他们也是一组相互关联的链接而已。
在编号列表中,使用数字一(1.)
对非排序列表,使用加号(+)、星号(*)、或者减号(-)
在每个列表之后留一个空行
对于嵌套的列表,相对缩进四个空格(例如,⋅⋅⋅⋅)。
列表条目可能包含多个段落。每个后续段落都要缩进或者四个空格或者一个制表符。
表格 数据表格的语义用途是呈现表格化的数据。
用户可以快速浏览表格,但屏幕抓取器需要逐行地处理数据。
表格标题可以用来给数据表提供一个描述性的标题。
辅助技术使用 HTML 表格标题元素来在页面结构中辨识表格内容。
内容最佳实践 本节包含一些建议的最佳实践,用来开发清晰、明确一致的文档内容。
使用现在时态 使用现在时态 可以 不可以 此命令启动代理。 此命令将启动一个代理。
例外:如果需要使用过去时或将来时来表达正确含义时,是可以使用的。
使用主动语态 使用主动语态 可以 不可以 你可以使用浏览器来浏览 API。 API 可以被使用浏览器来浏览。 YAML 文件给出副本个数。 副本个数是在 YAML 文件中给出的。
例外:如果主动语态会导致句子很难构造时,可以使用被动语态。
使用简单直接的语言 使用简单直接的语言。避免不必要的短语,例如说“请”。
使用简单直接语言 可以 不可以 要创建 ReplicaSet,... 如果你想要创建 ReplicaSet,... 参看配置文件。 请自行查看配置文件。 查看 Pods。 使用下面的命令,我们将会看到 Pods。
将读者称为“你” 将读者称为“你” 可以 不可以 你可以通过 ... 创建一个 Deployment。 通过...我们将创建一个 Deployment。 在前面的输出中,你可以看到... 在前面的输出中,我们可以看到...
避免拉丁短语 尽可能使用英语而不是拉丁语缩写。
避免拉丁语短语 可以 不可以 例如,... e.g., ... 也就是说,... i.e., ...
例外:使用 etc. 表示等等。
应避免的模式 避免使用“我们” 在句子中使用“我们”会让人感到困惑,因为读者可能不知道这里的
“我们”指的是谁。
要避免的模式 可以 不可以 版本 1.4 包含了 ... 在 1.4 版本中,我们添加了 ... Kubernetes 为 ... 提供了一项新功能。 我们提供了一项新功能... 本页面教你如何使用 Pods。 在本页中,我们将会学到如何使用 Pods。
避免使用俚语或行话 对某些读者而言,英语是其外语。
避免使用一些俚语或行话有助于他们更方便的理解内容。
避免使用俚语或行话 可以 不可以 Internally, ... Under the hood, ... Create a new cluster. Turn up a new cluster.
避免关于将来的陈述 要避免对将来作出承诺或暗示。如果你需要讨论的是 Alpha 功能特性,可以将相关文字
放在一个单独的标题下,标示为 alpha 版本信息。
避免使用很快就会过时的表达 避免使用一些很快就会过时的陈述,例如“目前”、“新的”。
今天而言是新的功能,过了几个月之后就不再是新的了。
避免使用很快过时的表达 可以 不可以 在版本 1.4 中,... 在当前版本中,... 联邦功能特性提供 ... 新的联邦功能特性提供 ...
接下来 7.7.3 - 撰写新主题 本页面展示如何为 Kubernetes 文档库创建新主题。
准备开始 如发起 PR 中所述,创建 Kubernetes 文档库的派生副本。
选择页面类型 当你准备编写一个新的主题时,考虑一下最适合你的内容的页面类型:
选择页面类型的说明 类型 描述 概念(Concept) 概念页面负责解释 Kubernetes 的某方面。例如,概念页面可以描述 Kubernetes Deployment 对象,并解释当部署、扩展和更新时,它作为应用程序所扮演的角色。一般来说,概念页面不包括步骤序列,而是提供任务或教程的链接。概念主题的示例可参见 节点 。 任务(Task) 任务页面展示如何完成特定任务。其目的是给读者提供一系列的步骤,让他们在阅读时可以实际执行。任务页面可长可短,前提是它始终围绕着某个主题展开。在任务页面中,可以将简短的解释与要执行的步骤混合在一起。如果需要提供较长的解释,则应在概念主题中进行。相关联的任务和概念主题应该相互链接。一个简短的任务页面的实例可参见 配置 Pod 使用卷存储 。一个较长的任务页面的实例可参见 配置活跃性和就绪性探针 。 教程(Tutorial) 教程页面展示如何实现某个目标,该目标将若干 Kubernetes 功能特性联系在一起。教程可能提供一些步骤序列,读者可以在阅读页面时实际执行这些步骤。或者它可以提供相关代码片段的解释。例如,教程可以提供代码示例的讲解。教程可以包括对 Kubernetes 几个关联特性的简要解释,但有关更深入的特性解释应该链接到相关概念主题。
为每个新页面选择其内容类型 。
使用页面类型有助于确保给定类型的各主题之间保持一致。
选择标题和文件名 选择一个标题,确保其中包含希望搜索引擎发现的关键字。
确定文件名时请使用标题中的单词,由连字符分隔。
例如,标题为Using an HTTP Proxy to Access Kubernetes API
的主题的文件名为 http-proxy-access-api.md。
你不需要在文件名中加上 "kubernetes",因为 "kubernetes" 已经在主题的 URL 中了,
例如:
/docs/tasks/extend-kubernetes/http-proxy-access-api/
在页面前言中添加主题标题 在你的主题中,在前言(front-matter)
中设置一个 title 字段。
前言是位于页面顶部三条虚线之间的 YAML 块。下面是一个例子:
---
title: 使用 HTTP 代理访问 Kubernetes API
---
选择目录 根据页面类型,将新文件放入其中一个子目录中:
/content/en/docs/tasks/ /content/en/docs/tutorials/ /content/en/docs/concepts/ 你可以将文件放在现有的子目录中,也可以创建一个新的子目录。
将主题放在目录中 目录是使用文档源的目录结构动态构建的。
/content/en/docs/ 下的顶层目录用于创建顶层导航条目,
这些目录和它们的子目录在网站目录中都有对应条目。
每个子目录都有一个 _index.md 文件,它表示的是该子目录内容的主页面。
_index.md 文件不需要模板。它可以包含各子目录中主题的概述内容。
默认情况下,目录中的其他文件按字母顺序排序。这一般不是最好的顺序。
要控制子目录中主题的相对排序,请将页面头部的键 weight: 设置为整数值。
通常我们使用 10 的倍数,添加后续主题时 weight 值递增。
例如,weight 为 10 的主题将位于 weight 为 20 的主题之前。
在主题中嵌入代码 如果你想在主题中嵌入一些代码,可以直接使用 Markdown 代码块语法将代码嵌入到文件中。
建议在以下场合(并非详尽列表)使用嵌入代码:
代码显示来自命令的输出,例如 kubectl get deploy mydeployment -o json | jq '.status'。 代码不够通用,用户无法验证。例如,你可以嵌入 YAML 文件来创建一个依赖于特定
FlexVolume 实现的 Pod。 该代码是一个不完整的示例,因为其目的是突出展现某个大文件中的部分内容。
例如,在描述出于某些原因定制
PodSecurityPolicy
的方法时,你可以在主题文件中直接提供一个短的代码段。 由于某些其他原因,该代码不适合用户验证。
例如,当使用 kubectl edit 命令描述如何将新属性添加到资源时,
你可以提供一个仅包含要添加的属性的简短示例。 引用来自其他文件的代码 在主题中引用代码的另一种方法是创建一个新的、完整的示例文件(或文件组),
然后在主题中引用这些示例。当示例是通用的和可重用的,并且你希望读者自己验证时,
使用此方法引用示例 YAML 文件。
添加新的独立示例文件(如 YAML 文件)时,将代码放在 <LANG>/examples/ 的某个子目录中,
其中 <LANG> 是该主题的语言。在主题文件中使用 codenew 短代码:
{{< codenew file="<RELPATH>/my-example-yaml>" >}}
<RELPATH> 是要引用的文件的路径,相对于 examples 目录。以下 Hugo
短代码引用了位于 /content/en/examples/pods/storage/gce-volume.yaml 的 YAML
文件。
{{< codenew file="pods/storage/gce-volume.yaml" >}}
说明: 要展示上述示例中的原始 Hugo 短代码并避免 Hugo 对其进行解释,
请直接在 < 字符之后和 > 字符之前使用 C 样式注释。请查看此页面的代码。
显示如何从配置文件创建 API 对象 如果需要演示如何基于配置文件创建 API 对象,请将配置文件放在 <LANG>/examples
下的某个子目录中。
在主题中展示以下命令:
kubectl create -f https://k8s.io/examples/pods/storage/gce-volume.yaml
说明: 将新的 YAML 文件添加到 <LANG>/examples 目录时,请确保该文件也在
<LANG>/examples_test.go 文件中被引用。
当提交拉取请求时,网站的 Travis CI 会自动运行此测试用例,以确保所有示例都通过测试。
有关使用此技术的主题的示例,请参见
运行单实例有状态的应用 。
向主题添加图片 将图片文件放入 /images 目录。首选的图片格式是 SVG。
接下来 7.7.4 - 页面内容类型 Kubernetes 文档包含以下几种页面内容类型:
概念(Concept) 任务(Task) 教程(Tutorial) 参考(Reference) 内容章节 每种页面内容类型都有一些使用 Markdown 注释和 HTML 标题定义的章节。
你可以使用 heading 短代码将内容标题添加到你的页面中。
注释和标题有助于维护对应页面内容类型的结构组织。
定义页面内容章节的 Markdown 注释示例:
要在内容页面中创建通用的标题,可以使用 heading 短代码加上标题字符串。
标题字符串示例:
whatsnext prerequisites objectives cleanup synopsis seealso options 例如,要创建一个 whatsnext 标题,添加 heading 短代码并指定 "whatsnext" 字符串:
## {{% heading "whatsnext" %}}
你可以像下面这样声明一个 prerequisites 标题:
## {{% heading "prerequisites" %}}
短代码 heading 需要一个字符串参数。
该字符串参数要与 i18n/<语言>.toml 文件中以其为前缀的某个变量匹配。
例如:
i18n/en.toml:
[whatsnext_heading]
other = "What's next"
i18n/ko.toml:
[whatsnext_heading]
other = "다음 내용"
内容类型 每种内容类型都非正式地定义了期望的页面结构组织。
请按照所建议的页面章节来创建内容页面。
概念 概念页面用来解释 Kubernetes 的某些方面。例如,概念页面可以用来描述 Kubernetes
中的 Deployment 对象,解释其作为应用的角色如何部署、扩缩和更新。
通常,概念页面不需要包含步骤序列,但包含指向任务或教程的链接。
要编写一个新的概念页面,在 /content/en/docs/concepts 目录下面的子目录中新建
一个 Markdown 文件。该文件具有以下特点。
概念页面分为三个章节:
页面章节 overview (概述) body (主体) whatsnext (接下来)
其中的 overview 和 body 章节在概念页面中显示为注释。
你可以使用 heading 短代码向页面添加 wahtsnext 节。
在为每个章节撰写内容时,遵从一些规定:
使用二级和三级标题(H2、H3)来组织内容 在 overview 节中,使用一段文字来为主体部分铺陈上下文; 在 body 节中,详细解释对应概念; 对于 whatsnext 节,提供一个项目符号列表(最多 5 个),帮助读者进一步学习掌握概念 注解 页面是一个已经
上线的概念页面的例子。
任务(Task) 任务页面讲解如何完成某项工作,通常包含由为数不多的几个步骤组成的序列。
任务页面的讲解文字很少,不过通常会包含指向概念主题的链接,以便读者
能够了解相关的背景和知识。
编写新的任务页面时,在 /content/en/docs/tasks 目录下的子目录中创建一个
新的 Markdown 文件。该文件特点如下。
页面章节 overview (概述) prerequisites (准备工作) steps (步骤) discussion (讨论) whatsnext (接下来)
其中的 overview、steps 和 discussion 节在任务页面中显示为注释。
你可以使用 heading 短代码添加 prerequisites 和 whatsnext 小节。
在每个小节内撰写内容时注意以下规定:
最低使用二级标题(H2,标题行前带两个 # 字符)。每个小节都会由模版自动给出标题。 在 overview 节中,用一个段落为整个任务主体设定语境; 在 prerequisites 节中,尽可能使用项目符号列表。
额外的环境准备条件要加在 include 短代码之后。
默认的环境准备条件是拥有一个在运行的 Kubernetes 集群。 在 steps 节中,使用编号符号列表。 在 discussion 节中,使用正常文字内容来对 steps 节中内容展开叙述。 在 whatsnext 节中,使用项目符号列表(不超过 5 项),列举读者可能接下来有兴趣
阅读的主题。 已上线的任务主题示例之一是使用 HTTP 代理来访问 Kubernetes API 。
教程(Tutorial) 教程页面描述如果完成一个比单一任务规模更大的目标。通常教程页面会有多个小节,
每个小节由一系列步骤组成。例如,每个教程可能提供对代码示例的讲解,便于用户
了解 Kubernetes 的某个功能特性。教程可以包含表面层面的概念解释,对于更深层面
的概念主题应该使用链接。
撰写新的教程页面时,在 /content/en/docs/tutorials 目录下面的子目录中创建新的
Markdown 文件。该文件有以下特点。
页面节区 overview (概述) prerequisites (环境准备) objectives (目标) lessoncontent (教程内容) cleanup (清理工作) whatsnext (接下来)
教程页面的 overview、objectives 和 lessoncontent 小节显示为注释形式。
你可以使用 heading 短代码根据需要添加 prerequisites、cleanup 和
whatsnext 小节。
在每个小节中编写内容时,请注意以下规定:
最低使用二级标题(H2,标题前面有两个 # 字符)。模版会自动为每个小节设置标题。 在 overview 节中,用一个段落为整个主题设定语境; 在 prerequisites 节中,尽可能使用项目符号列表。
额外的环境准备条件要加在已包含的条件之后。 在 objectives 节中,使用项目符号列表。 在 lessoncontent 节中,结合使用编号符号列表和叙述性文字。 在 cleanup 节中,使用编号符号列表来描述任务结束后清理集群状态所需要的步骤。 在 whatsnext 节中,使用项目符号列表(不超过 5 项),列举读者可能接下来有兴趣
阅读的主题。 已发布的教程主题的一个例子是
使用 Deployment 运行无状态应用 .
参考(Reference) 组件工具的参考页面给出的是某个 Kubernetes 组件工具的描述和参数选项输出。
每个页面都是使用组件工具命令基于脚本生成的。
每个工具参考页面可能包含以下小节:
页面小节 synopsis (用法) options(选项) options from parent commands (从父命令集成的选项) examples (示例) seealso (参考)
已发布的工具参考页面示例包括:
接下来 7.7.5 - 内容组织 本网站使用了 Hugo。在 Hugo 中,内容组织 是一个核心概念。
说明: Hugo 提示: 用 hugo server --navigateToChanged 命令启动 Hugo 以进行内容编辑会话。
页面列表 页面顺序 文档侧方菜单、文档页面浏览器等以 Hugo 的默认排序顺序列出。Hugo 会按照权重(从 1 开始)、
日期(最新的排最前面)排序,最后按链接标题排序。
有鉴于此,如果你想将一个页面或一个章节前移,请在页面头部设置一个较高的权重:
title : My Page
weight : 10
说明: 对于页面的权重,不建议使用连续的数值,比如1、2、3...,而应采用间隔的数值,比如10、20、30...
这样将来你可以将其他页面插入到想要的位置。
文档主菜单 文档 主菜单是从 docs/ 下面的章节构建的。
这些章节在其章节内容文件 _index.md 的头部设置了 main_menu 标志:
注意,链接标题来自页面的 linkTitle 字段,因此如果希望它与页面标题不同,请在内容文件中更改它:
main_menu : true
title : Page Title
linkTitle : Title used in links
说明: 以上操作需要为每种语言分别完成。如果在菜单中没有看到你的章节,这可能是因为它没有被 Hugo 识别为一个章节。
请在章节对应的目录下创建 _index.md 内容文件。
文档侧方菜单 文档侧方菜单是基于 docs/ 下面的 当前章节的内容树 构建的。
菜单默认显示所有的章节和它们的页面。
如果你不想列出某个章节或页面,请在页面头部将 toc_hide 标志设置为 true。
当导航到具有内容的章节时,网站将显示出指定的章节或页面(例如 _index.md)。
否则,将显示该章节里的第一个页面。
文档浏览器 文档主页上的页面浏览器是基于 docs section 下一层的所有章节和页面构建的。
如果你不想列出某个章节或页面,请在页面头部将 toc_hide 标志设置为 true。
主菜单 右上菜单中的网站链接(也出现在页脚中)是通过页面查找构建的。
这是为了确保页面实际存在。因此,如果 case-studies 章节在网站(或者其本地化版本)中不存在,
则不会出现对应的链接。
页面包 除了独立的内容页面(Markdown 文件),Hugo 还支持
页面包 。
一个例子是定制的 Hugo 短代码(shortcodes) 。
它被认为是 leaf bundle(叶子包)。
目录下的所有内容,包括 index.md,都是包的一部分。此外还包括页面间相对链接、可被处理的图像等:
en/docs/home/contribute/includes
├── example1.md
├── example2.md
├── index.md
└── podtemplate.json
另一个广泛使用的例子是 includes 包。
这类包在页面头部设置 headless: true,意味着它没有得到自己的 URL。它只用于其他页面。
en/includes
├── default-storage-class-prereqs.md
├── index.md
├── partner-script.js
├── partner-style.css
├── task-tutorial-prereqs.md
├── user-guide-content-moved.md
└── user-guide-migration-notice.md
有关包中文件的一些重要说明:
已翻译的包会从上面的语言继承所有缺失的、非内容文件。这一设计可以避免重复。 包中的所有文件都是 Hugo 所指的 Resources,你可以为用不同语言为其提供元数据,
例如参数和标题,即使它不支持头部设置(YAML 文件等)。
参见页面资源元数据 。 从 Resource 的 .RelPermalink 中获得的值是相对于当前页面的。
参见 Permalinks 。 样式 网站的样式表的 SASS 源文件存储在 src/sass 下面,可以用 make sass 构建
(Hugo 很快就提供 SASS 的支持,参见 https://github.com/gohugoio/hugo/issues/4243 )。
接下来 7.7.6 - 定制 Hugo 短代码 本页面将介绍 Hugo 自定义短代码,可以用于 Kubernetes Markdown 文档书写。
关于短代码的更多信息可参见 Hugo 文档 。
功能状态 在本站的 Markdown 页面中,你可以加入短代码来展示所描述的功能特性的版本和状态。
功能状态示例 下面是一个功能状态代码段的演示,表明这个功能已经在最新版 Kubernetes 中稳定了。
{{< feature-state state="stable" >}}
会转换为:
FEATURE STATE: Kubernetes v1.20 [stable]
state 的可选值如下:
alpha beta deprecated stable 功能状态代码 所显示的 Kubernetes 默认为该页或站点版本。
修改 for_k8s_version 短代码参数可以调整要显示的版本。例如
{{< feature-state for_k8s_version="v1.10" state="beta" >}}
会转换为:
FEATURE STATE: Kubernetes v1.10 [beta]
词汇 有两种词汇表提示:glossary_tooltip 和 glossary_definition。
你可以通过加入术语词汇的短代码,来自动更新和替换相应链接中的内容
(我们的词汇库 )
在浏览在线文档时,术语会显示为超链接的样式,当鼠标移到术语上时,其解释就会显示在提示框中。
除了包含工具提示外,你还可以重用页面内容中词汇表中的定义。
词汇术语的原始数据保存在 https://github.com/kubernetes/website/tree/master/content/en/docs/reference/glossary ,每个内容文件对应相应的术语解释。
词汇演示 例如,下面的代码在 Markdown 中将会转换为 cluster ,
然后在提示框中显示。
{{< glossary_tooltip text="cluster" term_id="cluster" >}}
这是一个简短的词汇表定义:
{{< glossary_definition prepend="A cluster is" term_id="cluster" length="short" >}}
呈现为:
A cluster is 集群由一组被称作节点的机器组成。这些节点上运行 Kubernetes 所管理的容器化应用。集群具有至少一个工作节点。
你也可以包括完整的定义:
{{< glossary_definition term_id="cluster" length="all" >}}
呈现为:
集群由一组被称作节点的机器组成。这些节点上运行 Kubernetes 所管理的容器化应用。集群具有至少一个工作节点。
工作节点托管作为应用负载的组件的 Pod 。控制平面管理集群中的工作节点和 Pod 。
为集群提供故障转移和高可用性,这些控制平面一般跨多主机运行,集群跨多个节点运行。
表格标题 通过添加表格标题,你可以让表格能够被屏幕阅读器读取。
要向表格添加标题(Caption) ,
可用 table 短代码包围表格定义,并使用 caption 参数给出表格标题。
说明: 表格标题对屏幕阅读器是可见的,但在标准 HTML 中查看时是不可见的。
下面是一个例子:
{{ < table caption= "配置参数" > }}
参数 | 描述 | 默认值
:---------|:------------|:-------
`timeout` | 请求的超时时长 | `30s`
`logLevel` | 日志输出的级别 | `INFO`
{{ < / table > }}
所渲染的表格如下:
配置参数 参数 描述 默认值 timeout请求的超时时长 30slogLevel日志输出的级别 INFO
如果你查看表格的 HTML 输出结果,你会看到 <table> 元素
后面紧接着下面的元素:
<caption style = "display: none;" >配置参数</caption >
标签页 在本站的 Markdown 页面(.md 文件)中,你可以加入一个标签页集来显示
某解决方案的不同形式。
标签页的短代码包含以下参数:
name: 标签页上显示的名字。codelang: 如果要在 tab 短代码中加入内部内容,需要告知 Hugo 使用的是什么代码语言,方便代码高亮。include: 标签页中所要包含的文件。如果标签页是在 Hugo 的
叶子包 中定义,
Hugo 会在包内查找文件(可以是 Hugo 所支持的任何 MIME 类型文件)。
否则,Hugo 会在当前路径的相对路径下查找所要包含的内容页面。
注意,在 include 页面中不能包含短代码内容,必须要使用自结束(self-closing)语法。
非内容文件将会被代码高亮。
如果没有在 codelang 进行声明的话,Hugo 会根据文件名推测所用的语言。如果内部内容是 Markdown,你必须要使用 % 分隔符来包装标签页。
例如,{{% tab name="Tab 1" %}}This is **markdown**{{% /tab %}}。 可以在标签页集中混合使用上面的各种变形。 下面是标签页短代码的示例。
说明: 内容页面下的 tabs 定义中的标签页 name 必须是唯一的。
标签页演示:代码高亮 {{ < tabs name= "tab_with_code" > }}
{{ {< tab name= "Tab 1" codelang= "bash" > }}
echo "This is tab 1."
{{ < / tab > }}
{{ < tab name= "Tab 2" codelang= "go" > }}
println "This is tab 2."
{{ < / tab > }} }
{{ < / tabs > }}
会转换为:
标签页演示:内联 Markdown 和 HTML {{ < tabs name= "tab_with_md" > }}
{{ % tab name= "Markdown" % }}
这是 **一些 markdown 。**
{{ < note > }} 它甚至可以包含短代码。{{ < / note > }}
{{ % / tab % }}
{{ < tab name= "HTML" > }}
<div >
<h3 >纯 HTML</h3 >
<p >这是一些 <i >纯</i > HTML 。</p >
</div >
{{ < / tab > }}
{{ < / tabs > }}
会转换为:
这是 一些 markdown 。
说明: 它甚至可以包含短代码。
标签页演示:文件嵌套 {{ < tabs name= "tab_with_file_include" > }}
{{ < tab name= "Content File #1" include= "example1" /> }}
{{ < tab name= "Content File #2" include= "example2" /> }}
{{ < tab name= "JSON File" include= "podtemplate" /> }}
{{ < / tabs > }}
会转换为:
这是一个内容文件示例 ,位于一个includes 叶子包中。
说明: 被包含的内容文件也可以包含短代码。
这是另一个内容文件示例 ,位于一个includes 叶子包中。
{
"apiVersion" : "v1" ,
"kind" : "PodTemplate" ,
"metadata" : {
"name" : "nginx"
},
"template" : {
"metadata" : {
"labels" : {
"name" : "nginx"
},
"generateName" : "nginx-"
},
"spec" : {
"containers" : [{
"name" : "nginx" ,
"image" : "dockerfile/nginx" ,
"ports" : [{"containerPort" : 80 }]
}]
}
}
}
版本号信息 要在文档中生成版本号信息,可以从以下几种短代码中选择。每个短代码可以基于站点配置文件
config.toml 中的版本参数生成一个版本号取值。最常用的参数为 latest 和 version。
{{< param "version" >}}{{< param "version" >}} 短代码可以基于站点参数 version 生成 Kubernetes
文档的当前版本号取值。短代码 param 允许传入一个站点参数名称,在这里是 version。
说明: 在先前已经发布的文档中,latest 和 version 参数值并不完全等价。新版本文档发布后,参数
latest 会增加,而 version 则保持不变。例如,在上一版本的文档中使用 version 会得到
v1.19,而使用 latest 则会得到 v1.20。
转换为:
v1.20
{{< latest-version >}}{{< latest-version >}} 返回站点参数 latest 的取值。每当新版本文档发布时,该参数均会被更新。
因此,参数 latest 与 version 并不总是相同。
转换为:
v1.24
{{< latest-semver >}}{{< latest-semver >}} 短代码可以生成站点参数 latest 不含前缀 v 的版本号取值。
转换为:
1.24
{{< version-check >}}{{< version-check >}} 会检查是否设置了页面参数 min-kubernetes-server-version
并将其与 version 进行比较。
转换为:
要获知版本信息,请输入
kubectl version.
{{< latest-release-notes >}}{{< latest-release-notes >}} 短代码基于站点参数 latest 生成不含前缀 v
的版本号取值,并输出该版本更新日志的超链接地址。
转换为:
https://git.k8s.io/kubernetes/CHANGELOG/CHANGELOG-1.24.md
接下来 7.8 - 高级贡献 如果你已经了解如何贡献新内容 和
评阅他人工作 ,并准备了解更多贡献的途径,
请阅读此文。您需要使用 Git 命令行工具和其他工具做这些工作。
提出改进建议 SIG Docs 的 成员 可以提出改进建议。
在对 Kubernetes 文档贡献了一段时间后,你可能会对样式指南 、
内容指南 、用于构建文档的工具链、网站样式、
评审和合并 PR 的流程或者文档的其他方面产生改进的想法。
为了尽可能透明化,这些提议都需要在 SIG Docs 会议或
kubernetes-sig-docs 邮件列表 上讨论。
此外,在提出全面的改进之前,这些讨论能真正帮助我们了解有关“当前工作如何运作”和“以往的决定是为何做出”的背景。
想了解文档的当前运作方式,最快的途径是咨询 kubernetes.slack.com
中的 #sig-docs 聊天群组。
在进行了讨论并且 SIG 就期望的结果达成一致之后,你就能以最合理的方式处理改进建议了。例如,样式指南或网站功能的更新可能涉及 PR 的新增,而与文档测试相关的更改可能涉及 sig-testing。
为 Kubernetes 版本发布协调文档工作 SIG Docs 的批准者(approvers) 可以为
Kubernetes 版本发布协调文档工作。
每一个 Kubernetes 版本都是由参与 sig-release 的 SIG(特别兴趣小组)的一个团队协调的。
指定版本的发布团队中还包括总体发布牵头人,以及来自 sig-testing 的代表等。
要了解更多关于 Kubernetes 版本发布的流程,请参考
https://github.com/kubernetes/sig-release 。
SIG Docs 团队的代表需要为一个指定的版本协调以下工作:
通过特性跟踪表来监视新功能特性或现有功能特性的修改。
如果版本的某个功能特性的文档没有为发布做好准备,那么该功能特性不允许进入发布版本。 定期参加 sig-release 会议并汇报文档的发布状态。 评审和修改由负责实现某功能特性的 SIG 起草的功能特性文档。 合入版本发布相关的 PR,并为对应发布版本维护 Git 特性分支。 指导那些想学习并有意愿担当该角色的 SIG Docs 贡献者。这就是我们常说的“实习”。 发布版本的组件发布时,相关的文档更新也需要发布。 协调一个版本发布通常需要 3-4 个月的时间投入,该任务由 SIG Docs 批准人轮流承担。
担任新的贡献者大使 SIG Docs 批准人(Approvers)
可以担任新的贡献者大使。
新的贡献者大使共同努力欢迎 SIG-Docs 的新贡献者,对新贡献者的 PR 提出建议,
以及在前几份 PR 提交中指导新贡献者。
新的贡献者大使的职责包括:
监听 Kubernetes #sig-docs 频道 上新贡献者的 Issue。 与 PR 管理者合作为新参与者寻找合适的第一个 issues。 通过前几个 PR 指导新贡献者为文档存储库作贡献。 帮助新的贡献者创建成为 Kubernetes 成员所需的更复杂的 PR。 为贡献者提供保荐 ,使其成为 Kubernetes 成员。当前新贡献者大使将在每次 SIG 文档会议上以及 Kubernetes #sig-docs 频道 中宣布。
SIG Docs 的评审人(Reviewers) 可以为新的贡献者提供保荐。
新的贡献者针对一个或多个 Kubernetes 项目仓库成功提交了 5 个实质性 PR 之后,
就有资格申请 Kubernetes 组织的成员身份 。
贡献者的成员资格需要同时得到两位评审人的保荐。
新的文档贡献者可以通过咨询 Kubernetes Slack 实例
上的 #sig-docs 频道或者 SIG Docs 邮件列表
来请求评审者保荐。如果你对申请人的工作充满信心,你自愿保荐他们。
当他们提交成员资格申请时,回复 “+1” 并详细说明为什么你认为申请人适合加入 Kubernetes 组织。
担任 SIG 联合主席 SIG Docs 批准人(Approvers)
可以担任 SIG Docs 的联合主席。
前提条件 Approvers 必须满足以下要求才能成为联合主席:
职责范围 联合主席主要提供以下服务:
联合主席负责处理流程和政策、时间安排和召开会议、安排 PR 管理员、以及一些其他人不想做的事情,目的是增长贡献者团队。
职责范围包括:
保持 SIG Docs 专注于通过出色的文档最大限度地提高开发人员的满意度 以身作则,践行社区行为准则 ,
并要求 SIG 成员对自身行为负责 通过更新贡献指南,为 SIG 学习并设置最佳实践 安排和举行 SIG 会议:每周状态更新,每季度回顾/计划会议以及其他需要的会议 在 KubeCon 活动和其他会议上安排和负责文档工作 与 CNCF 及其尊贵合作伙伴
(包括 Google、Oracle、Azure、IBM 和华为)一起以 SIG Docs 的身份招募和宣传 负责 SIG 正常运行 召开高效的会议 为了安排和召开高效的会议,这些指南说明了如何做、怎样做以及原因。
坚持社区行为准则 :
设定明确的议程 :
对于每周一次的会议,请将前一周的笔记复制并粘贴到笔记的“过去的会议”部分中
通过协作,完成准确的记录 :
清晰准确地分配执行项目 :
根据需要来进行协调 :
如果讨论偏离议程,请让参与者重新关注当前主题 为不同的讨论风格留出空间,同时保持讨论重点并尊重人们的时间 尊重大家的时间 :
有效利用 Zoom :
录制 Zoom 会议 准备开始录制时,请单击“录制到云”。
准备停止录制时,请单击“停止”。
视频会自动上传到 YouTube。
8 - 测试页面(中文版) 本页面服务于两个目的:
展示 Kubernetes 中文版文档中应如何使用 Markdown 提供一个测试用文档,用来测试可能影响所有文档的 HTML、CSS 和模板变更 标题级别 上面的标题是 H2 级别。页面标题(Title)会渲染为 H1。以下各节分别展示 H3-H6
的渲染结果。
H3 此处为 H3 节内容。
H4 此处为 H4 节内容。
H5 此处为 H5 节内容。
H6 此处为 H6 节内容。
内联元素(Inline elements) 内联元素显示在段落文字、列表条目、提醒信息或者块级别元素之内。
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor
incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis
nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu
fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in
culpa qui officia deserunt mollit anim id est laborum.
内联文本风格 粗体字 斜体字 粗斜体字 删除线下划线 带下划线的斜体 带下划线的粗斜体 monospace text <- 等宽字体monospace bold <- 粗等宽字体列表 Markdown 在如何处理列表方面没有严格的规则。在我们从 Jekyll 迁移到 Hugo 时,
我们遇到了一些问题。为了处理这些问题,请注意以下几点:
项目符号列表 你可以将 - 和 * 混合使用要开始子列表,缩进两个 TAB (四个空格)。Jekyll 和 Markdown
在这点上有所不同 。 另一个子条目 编号列表 此为列表条目 此为列表中的第二个条目。在 Markdown 源码中所给的编号数字与最终输出的数字
可能不同。建议在紧凑列表中编号都使用 1。如果条目之间有其他内容(比如注释
掉的英文)存在,则需要显式给出编号。 说明: 对于单个数字的编号列表,在句点(.)后面加两个空格。这样有助于将列表的
内容更好地对齐。
这是一个新的列表。 使用 Hugo 时,你需要用 HTML 注释将两个紧挨着的列表分开。
HTML 注释需要按左边顶边对齐。
编号列表条目中也可以包含额外的段落或者块元素。
后续段落应该按编号列表文字的第一行左侧对齐。
此段落及下面的代码段都与本条目中的第一个字“编”对齐。
编号列表条目中可以在块级内容之后有子列表。子列表的符号项要与上层列表条目
文字左侧对齐。 中文译文的编号列表格式 1 译文条目一 译文条目二,由于前述原因,条目 2 与 1 之间存在注释行,如果此条目不显式给出
起始编号,会被 Hugo 当做两个独立的列表。 中文译文的编号列表格式 2 译文条目一
中文译文段落。
带注释的代码段(注意以上英文注释 <!-- 和 --> 的缩进空格数 )。
译文条目二,由于前述原因,条目 2 与 1 之间存在注释行,如果此条目不显式给出
起始编号,会被 Hugo 当做两个独立的列表。 标签列表 标签列表可以用来有条件地显式内容,例如,当有多种选项可供选择时,每个选项
可能需要完全不同的指令或者上下文。
标签页中也可以包含嵌套的排版风格,其中的英文注释处理也同正文中
的处理基本一致。
编号列表 (或者没有编号的) 列表
在标签页中的子标题 标签页中也可以包含嵌套的子标题。
警告: 标签页中的子标题不会在目录中出现。
检查项列表 (Checklists) 检查项列表本质上也是一种项目符号列表,只是这里的项目符号部分被 CSS 压制了。
代码段 你可以用两种方式来创建代码块。一种方式是将在代码块之前和之后分别加上包含三个
反引号的独立行。反引号应该仅用于代码段。
用这种方式标记代码段时,你还可以指定所包含的代码的编程语言,从而启用语法加亮。
这种方式也比使用空格缩进的方式可预测性更好。
这是用反引号创建的代码段
反引号标记代码段的方式有以下优点:
这种方式几乎总是能正确工作 在查看源代码时,内容相对紧凑 允许你指定代码块的编程语言,以便启用语法加亮 代码段的结束位置有明确标记。有时候,采用缩进空格的方式会使得一些对空格
很敏感的语言(如 Python、YAML)很难处理。 要为代码段指定编程语言,可以在第一组反引号之后加上编程语言名称:
Kubernetes 文档中代码块常用语言包括:
bash / shell (二者几乎完全相同)gojsonyamlxmlnone (禁止对代码块执行语法加亮)包含 Hugo 短代码的代码块 如果要像上面的例子一样显示 Hugo 短代码(Shortcode),不希望 Hugo 将其当做短代码来处理,
可以在 < 和 > 之间使用 C 语言风格的注释。
下面的示例展示如何实现这点(查看本页的 Markdown 源码):
{{< codenew file="pods/storage/gce-volume.yaml" >}}
链接 要格式化链接,将链接显示文本放在方括号中,后接用圆括号括起来的链接目标。
指向 Kubernetes.io 的连接 或
到 Kubernetes.io 的相对链接 。
你也可以使用 HTML,但这种方式不是推荐的方式。
到 Kubernetes.io 的链接 。
中文链接 中文版本文档中的链接要注意以下两点:
指向 Kubernetes 文档的站内链接,需要在英文链接之前添加前缀 /zh。
例如,原链接目标为 /docs/foo/bar 时,译文中的链接目标应为
/zh/docs/foo/bar。例如:
英文页面子标题会生成对应锚点(Anchor),例如子标题 ## Using object 会生成
对应标签 #using-objects。在翻译为中文之后,对应锚点可能会失效。对此,有
两种方法处理。假定译文中存在以下子标题:
<!--
## Clean up
You can do this ...
-->
## 清理现场
你可以这样 ...
并且在本页或其他页面有指向 #clean-up 的链接如下:
..., please refer to the [clean up](#clean-up) section.
第一种处理方法是将链接改为中文锚点,即将引用该子标题的文字全部改为中文锚点。
例如:
..., 请参考[清理工作](#清理现场)一节。
第二种方式(也是推荐的方式)是将原来可能生成的锚点(尽管在英文原文中未明确
给出)显式标记在译文的子标题上。
<!--
## Clean up
You can do this ...
-->
## 清理现场 {#clean-up}
你可以这样 ...
之所以优选第二种方式是因为可以避免文档站点中其他引用此子标题的链接失效。
图片 要显示图片,可以使用与链接类似的语法([links](#links)),不过要在整个链接
之前添加一个感叹号(!)。方括号中给出的是图片的替代文本。
请坚持为图片设定替代文本,这样使用屏幕阅读器的人也能够了解图片中包含的是什么。
要设置扩展的属性,例如 width、title、caption 等等,可以使用
figure
短代码,而不是使用 HTML 的 <img> 标签。
此外,如果你需要让图片本身变成超链接,可以使用短代码的 link 属性,而不是
将整个图片放到 Markdown 的链接语法之内。下面是一个例子:
铅笔图标 用来展示 figure 短代码的图片
即使你不想使用 figure 短代码,图片也可以展示为链接。这里,铅笔图标指向
Kubernetes 网站。外层的方括号将整个 image 标签封装起来,链接目标在
末尾的圆括号之间给出。
你也可以使用 HTML 来嵌入图片,不过这种方式是不推荐的。
表格 简单的表格可能每行只有一个独立的数据行,各个列之间用 | 隔开。
表格的标题行与表格内容之间用独立的一行隔开,在这一行中每个单元格的内容
只有 - 字符,且至少三个。出于方便维护考虑,请尝试将各个单元格间的
分割线对齐,尽管这样意味着你需要多输入几个空格。
标题单元格 1 标题单元格 2 内容单元格 1 内容单元格 2
标题行是可选的。所有用 | 隔开的内容都会被渲染成表格。
Markdown 表格在处理块级元素方面还很笨拙。例如在单元格中嵌入列表条目、代码段、
或者在其中划分多个段落方面的能力都比较差。对于复杂的或者很宽的表格,可以使用
HTML。
标题单元格 1 标题单元格 2 内容单元格 1 内容单元格 2
使用 Mermaid 来可视化 你可以使用 Mermaid JS 来进行可视化展示。
Mermaid JS 版本在 /layouts/partials/head.html
中设置。
{{< mermaid >}}
graph TD;
甲-->乙;
甲-->丙;
乙-->丁;
丙-->丁;
{{</ mermaid >}}
会产生:
graph TD;
甲-->乙;
甲-->丙;
乙-->丁;
丙-->丁;
[JavaScript must be enabled to view content] {{< mermaid >}}
sequenceDiagram
张三 ->> 李四: 李四,锄禾日当午?
李四-->>王五: 王五,锄禾日当午?
李四--x 张三: 汗滴禾下土!
李四-x 王五: 汗滴禾下土!
Note right of 王五: 李四想啊想啊<br/>一直想啊想,太阳<br/>都下山了,他还没想出来<br/>,文本框都放不下了。
李四-->张三: 跑去问王五...
张三->王五: 好吧... 王五,白日依山尽?
{{</ mermaid >}}
产生:
sequenceDiagram
张三 ->> 李四: 李四,锄禾日当午?
李四-->>王五: 王五,锄禾日当午?
李四--x 张三: 汗滴禾下土!
李四-x 王五: 汗滴禾下土!
Note right of 王五: 李四想啊想啊一直想, 想到太阳都下山了, 他还没想出来, 文本框都放不下了。
李四-->张三: 跑去问王五...
张三->王五: 好吧... 王五,白日依山尽?
[JavaScript must be enabled to view content] 在官方网站上有更多的示例 。
侧边栏和提醒框 侧边栏和提醒框可以为文本提供直观的重要性强调效果,可以偶尔一用。
侧边栏可以将文字横向平移,只是其显示效果可能不像提醒 那么明显。
此为侧边栏。
你可以在侧边栏内排版段落和块级元素。
你甚至可以在其中包含代码块。
提醒框 提醒框(说明、警告等等)都是用 Hugo 短代码的形式展现。
说明: 说明信息用来引起读者的注意,但不过分强调其紧迫性。
你可以在提醒框内包含多个段落和块级元素。
| 甚至 | 包含 | 表格 |
注意: 读者继续此操作时要格外小心。
警告: 警告信息试图为读者指出一些不应忽略的、可能引发问题的事情。
注意,在较老的 Hugo 版本中,直接将 note、warning 或 caution 短代码
括入 HTML 注释当中是有问题的。这些短代码仍然会起作用。目前,在 0.70.0
以上版本中似乎已经修复了这一问题。
包含其他页面 要包含其他页面,可使用短代码。
说明: 你必须拥有一个 Kubernetes 的集群,同时你的 Kubernetes 集群必须带有 kubectl 命令行工具。
如果你还没有集群,你可以通过 Minikube 构建一
个你自己的集群,或者你可以使用下面任意一个 Kubernetes 工具构建:
嵌入的 Katacoda 环境
Launch Terminal